blob: f7fc725707664cd04cedc007f57317a180682c2e [file] [log] [blame]
Simon Glass83b9be62022-04-24 23:31:26 -06001.. SPDX-License-Identifier: GPL-2.0+:
2
3U-Boot Standard Boot
4====================
5
6Introduction
7------------
8
9Standard boot provides a built-in way for U-Boot to automatically boot
10an Operating System without custom scripting and other customisation. It
11introduces the following concepts:
12
13 - bootdev - a device which can hold or access a distro (e.g. MMC, Ethernet)
14 - bootmeth - a method to scan a bootdev to find bootflows (e.g. distro boot)
15 - bootflow - a description of how to boot (provided by the distro)
16
17For Linux, the distro (Linux distribution, e.g. Debian, Fedora) is responsible
18for creating a bootflow for each kernel combination that it wants to offer.
19These bootflows are stored on media so they can be discovered by U-Boot. This
20feature is typically called `distro boot` (see :doc:`distro`) because it is
21a way for distributions to boot on any hardware.
22
23Traditionally U-Boot has relied on scripts to implement this feature. See
Paul Barker6c55d0d2022-07-29 14:31:58 +010024distro_bootcmd_ for details. This is done because U-Boot has no native support
Simon Glass83b9be62022-04-24 23:31:26 -060025for scanning devices. While the scripts work remarkably well, they can be hard
26to understand and extend, and the feature does not include tests. They are also
27making it difficult to move away from ad-hoc CONFIGs, since they are implemented
28using the environment and a lot of #defines.
29
30Standard boot is a generalisation of distro boot. It provides a more built-in
31way to boot with U-Boot. The feature is extensible to different Operating
32Systems (such as Chromium OS) and devices (beyond just block and network
33devices). It supports EFI boot and EFI bootmgr too.
34
Simon Glassc08a9922022-07-30 15:52:03 -060035Finally, standard boot supports the operation of :doc:`vbe`.
Simon Glass83b9be62022-04-24 23:31:26 -060036
37Bootflow
38--------
39
40A bootflow is a file that describes how to boot a distro. Conceptually there can
41be different formats for that file but at present U-Boot only supports the
42BootLoaderSpec_ format. which looks something like this::
43
44 menu autoboot Welcome to Fedora-Workstation-armhfp-31-1.9. Automatic boot in # second{,s}. Press a key for options.
45 menu title Fedora-Workstation-armhfp-31-1.9 Boot Options.
46 menu hidden
47
48 label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
49 kernel /vmlinuz-5.3.7-301.fc31.armv7hl
50 append ro root=UUID=9732b35b-4cd5-458b-9b91-80f7047e0b8a rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB
51 fdtdir /dtb-5.3.7-301.fc31.armv7hl/
52 initrd /initramfs-5.3.7-301.fc31.armv7hl.img
53
54As you can see it specifies a kernel, a ramdisk (initrd) and a directory from
Paul Barker6c55d0d2022-07-29 14:31:58 +010055which to load devicetree files. The details are described in distro_bootcmd_.
Simon Glass83b9be62022-04-24 23:31:26 -060056
57The bootflow is provided by the distro. It is not part of U-Boot. U-Boot's job
58is simply to interpret the file and carry out the instructions. This allows
59distros to boot on essentially any device supported by U-Boot.
60
61Typically the first available bootflow is selected and booted. If that fails,
62then the next one is tried.
63
64
65Bootdev
66-------
67
68Where does U-Boot find the media that holds the operating systems? That is the
69job of bootdev. A bootdev is simply a layer on top of a media device (such as
70MMC, NVMe). The bootdev accesses the device, including partitions and
71filesystems that might contain things related to an operating system.
72
73For example, an MMC bootdev provides access to the individual partitions on the
74MMC device. It scans through these to find filesystems, then provides a list of
75these for consideration.
76
77
78Bootmeth
79--------
80
81Once the list of filesystems is provided, how does U-Boot find the bootflow
82files in these filesystems. That is the job of bootmeth. Each boot method has
83its own way of doing this.
84
85For example, the distro bootmeth simply looks through the provided filesystem
86for a file called `extlinux/extlinux.conf`. This files constitutes a bootflow.
87If the distro bootmeth is used on multiple partitions it may produce multiple
88bootflows.
89
90Note: it is possible to have a bootmeth that uses a partition or a whole device
91directly, but it is more common to use a filesystem.
92
Simon Glassafaeb772022-07-30 15:52:35 -060093Note that some bootmeths are 'global', meaning that they select the bootdev
94themselves. Examples include VBE and EFI boot manager. In this case, they
95provide a `read_bootflow()` method which checks whatever bootdevs it likes, then
96returns the bootflow, if found. Some of these bootmeths may be very slow, if
97they scan a lot of devices.
98
Simon Glass83b9be62022-04-24 23:31:26 -060099
100Boot process
101------------
102
103U-Boot tries to use the 'lazy init' approach whereever possible and distro boot
104is no exception. The algorithm is::
105
106 while (get next bootdev)
107 while (get next bootmeth)
108 while (get next bootflow)
109 try to boot it
110
111So U-Boot works its way through the bootdevs, trying each bootmeth in turn to
112obtain bootflows, until it either boots or exhausts the available options.
113
114Instead of 500 lines of #defines and a 4KB boot script, all that is needed is
115the following command::
116
117 bootflow scan -lb
118
119which scans for available bootflows, optionally listing each find it finds (-l)
120and trying to boot it (-b).
121
Simon Glassafaeb772022-07-30 15:52:35 -0600122When global bootmeths are available, these are typically checked before the
123above bootdev scanning.
124
Simon Glass83b9be62022-04-24 23:31:26 -0600125
126Controlling ordering
127--------------------
128
129Several options are available to control the ordering of boot scanning:
130
131
132boot_targets
133~~~~~~~~~~~~
134
135This environment variable can be used to control the list of bootdevs searched
136and their ordering, for example::
137
138 setenv boot_targets "mmc0 mmc1 usb pxe"
139
140Entries may be removed or re-ordered in this list to affect the boot order. If
141the variable is empty, the default ordering is used, based on the priority of
142bootdevs and their sequence numbers.
143
144
145bootmeths
146~~~~~~~~~
147
148This environment variable can be used to control the list of bootmeths used and
149their ordering for example::
150
151 setenv bootmeths "syslinux efi"
152
153Entries may be removed or re-ordered in this list to affect the order the
154bootmeths are tried on each bootdev. If the variable is empty, the default
155ordering is used, based on the bootmeth sequence numbers, which can be
156controlled by aliases.
157
158The :ref:`usage/cmd/bootmeth:bootmeth command` (`bootmeth order`) operates in
159the same way as setting this variable.
160
161
162Bootdev uclass
163--------------
164
165The bootdev uclass provides an simple API call to obtain a bootflows from a
166device::
167
168 int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
169 struct bootflow *bflow);
170
171This takes a iterator which indicates the bootdev, partition and bootmeth to
172use. It returns a bootflow. This is the core of the bootdev implementation. The
173bootdev drivers that implement this differ depending on the media they are
174reading from, but each is responsible for returning a valid bootflow if
175available.
176
177A helper called `bootdev_find_in_blk()` makes it fairly easy to implement this
178function for each media device uclass, in a few lines of code.
179
180
181Bootdev drivers
182---------------
183
184A bootdev driver is typically fairly simple. Here is one for mmc::
185
186 static int mmc_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
187 struct bootflow *bflow)
188 {
189 struct udevice *mmc_dev = dev_get_parent(dev);
190 struct udevice *blk;
191 int ret;
192
193 ret = mmc_get_blk(mmc_dev, &blk);
194 /*
195 * If there is no media, indicate that no more partitions should be
196 * checked
197 */
198 if (ret == -EOPNOTSUPP)
199 ret = -ESHUTDOWN;
200 if (ret)
201 return log_msg_ret("blk", ret);
202 assert(blk);
203 ret = bootdev_find_in_blk(dev, blk, iter, bflow);
204 if (ret)
205 return log_msg_ret("find", ret);
206
207 return 0;
208 }
209
210 static int mmc_bootdev_bind(struct udevice *dev)
211 {
212 struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
213
214 ucp->prio = BOOTDEVP_0_INTERNAL_FAST;
215
216 return 0;
217 }
218
219 struct bootdev_ops mmc_bootdev_ops = {
220 .get_bootflow = mmc_get_bootflow,
221 };
222
223 static const struct udevice_id mmc_bootdev_ids[] = {
224 { .compatible = "u-boot,bootdev-mmc" },
225 { }
226 };
227
228 U_BOOT_DRIVER(mmc_bootdev) = {
229 .name = "mmc_bootdev",
230 .id = UCLASS_BOOTDEV,
231 .ops = &mmc_bootdev_ops,
232 .bind = mmc_bootdev_bind,
233 .of_match = mmc_bootdev_ids,
234 };
235
236The implementation of the `get_bootflow()` method is simply to obtain the
237block device and call a bootdev helper function to do the rest. The
238implementation of `bootdev_find_in_blk()` checks the partition table, and
239attempts to read a file from a filesystem on the partition number given by the
240`@iter->part` parameter.
241
242Each bootdev has a priority, which indicates the order in which it is used.
243Faster bootdevs are used first, since they are more likely to be able to boot
244the device quickly.
245
246
247Device hierarchy
248----------------
249
250A bootdev device is a child of the media device. In this example, you can see
251that the bootdev is a sibling of the block device and both are children of
252media device::
253
254 mmc 0 [ + ] bcm2835-sdhost | |-- mmc@7e202000
255 blk 0 [ + ] mmc_blk | | |-- mmc@7e202000.blk
256 bootdev 0 [ ] mmc_bootdev | | `-- mmc@7e202000.bootdev
257 mmc 1 [ + ] sdhci-bcm2835 | |-- sdhci@7e300000
258 blk 1 [ ] mmc_blk | | |-- sdhci@7e300000.blk
259 bootdev 1 [ ] mmc_bootdev | | `-- sdhci@7e300000.bootdev
260
261The bootdev device is typically created automatically in the media uclass'
262`post_bind()` method by calling `bootdev_setup_for_dev()`. The code typically
263something like this::
264
265 ret = bootdev_setup_for_dev(dev, "eth_bootdev");
266 if (ret)
267 return log_msg_ret("bootdev", ret);
268
269Here, `eth_bootdev` is the name of the Ethernet bootdev driver and `dev`
270is the ethernet device. This function is safe to call even if standard boot is
271not enabled, since it does nothing in that case. It can be added to all uclasses
272which implement suitable media.
273
274
275The bootstd device
276------------------
277
278Standard boot requires a single instance of the bootstd device to make things
279work. This includes global information about the state of standard boot. See
280`struct bootstd_priv` for this structure, accessed with `bootstd_get_priv()`.
281
Simon Glassafaeb772022-07-30 15:52:35 -0600282Within the devicetree, if you add bootmeth devices, they should be children of
283the bootstd device. See `arch/sandbox/dts/test.dts` for an example of this.
Simon Glass83b9be62022-04-24 23:31:26 -0600284
Simon Glass83b9be62022-04-24 23:31:26 -0600285
286.. _`Automatic Devices`:
287
288Automatic devices
289-----------------
290
291It is possible to define all the required devices in the devicetree manually,
292but it is not necessary. The bootstd uclass includes a `dm_scan_other()`
293function which creates the bootstd device if not found. If no bootmeth devices
Simon Glassafaeb772022-07-30 15:52:35 -0600294are found at all, it creates one for each available bootmeth driver.
Simon Glass83b9be62022-04-24 23:31:26 -0600295
296If your devicetree has any bootmeth device it must have all of them that you
Simon Glassafaeb772022-07-30 15:52:35 -0600297want to use, since no bootmeth devices will be created automatically in that
298case.
Simon Glass83b9be62022-04-24 23:31:26 -0600299
300
301Using devicetree
302----------------
303
304If a bootdev is complicated or needs configuration information, it can be
305added to the devicetree as a child of the media device. For example, imagine a
306bootdev which reads a bootflow from SPI flash. The devicetree fragment might
307look like this::
308
309 spi@0 {
310 flash@0 {
311 reg = <0>;
312 compatible = "spansion,m25p16", "jedec,spi-nor";
313 spi-max-frequency = <40000000>;
314
315 bootdev {
316 compatible = "u-boot,sf-bootdev";
317 offset = <0x2000>;
318 size = <0x1000>;
319 };
320 };
321 };
322
323The `sf-bootdev` driver can implement a way to read from the SPI flash, using
324the offset and size provided, and return that bootflow file back to the caller.
325When distro boot wants to read the kernel it calls disto_getfile() which must
326provide a way to read from the SPI flash. See `distro_boot()` at distro_boot_
327for more details.
328
329Of course this is all internal to U-Boot. All the distro sees is another way
330to boot.
331
332
333Configuration
334-------------
335
336Standard boot is enabled with `CONFIG_BOOTSTD`. Each bootmeth has its own CONFIG
337option also. For example, `CONFIG_BOOTMETH_DISTRO` enables support for distro
338boot from a disk.
339
340
341Available bootmeth drivers
342--------------------------
343
344Bootmeth drivers are provided for:
345
346 - distro boot from a disk (syslinux)
347 - distro boot from a network (PXE)
348 - EFI boot using bootefi
Simon Glassafaeb772022-07-30 15:52:35 -0600349 - VBE
Simon Glass83b9be62022-04-24 23:31:26 -0600350 - EFI boot using boot manager
351
352
353Command interface
354-----------------
355
356Three commands are available:
357
358`bootdev`
359 Allows listing of available bootdevs, selecting a particular one and
360 getting information about it. See :doc:`../usage/cmd/bootdev`
361
362`bootflow`
363 Allows scanning one or more bootdevs for bootflows, listing available
364 bootflows, selecting one, obtaining information about it and booting it.
365 See :doc:`../usage/cmd/bootflow`
366
367`bootmeth`
368 Allow listing of available bootmethds and setting the order in which they
369 are tried. See :doc:`../usage/cmd/bootmeth`
370
371.. _BootflowStates:
372
373Bootflow states
374---------------
375
376Here is a list of states that a bootflow can be in:
377
378======= =======================================================================
379State Meaning
380======= =======================================================================
381base Starting-out state, indicates that no media/partition was found. For an
382 SD card socket it may indicate that the card is not inserted.
383media Media was found (e.g. SD card is inserted) but no partition information
384 was found. It might lack a partition table or have a read error.
385part Partition was found but a filesystem could not be read. This could be
386 because the partition does not hold a filesystem or the filesystem is
387 very corrupted.
388fs Filesystem was found but the file could not be read. It could be
389 missing or in the wrong subdirectory.
390file File was found and its size detected, but it could not be read. This
391 could indicate filesystem corruption.
392ready File was loaded and is ready for use. In this state the bootflow is
393 ready to be booted.
394======= =======================================================================
395
396
397Theory of operation
398-------------------
399
400This describes how standard boot progresses through to booting an operating
401system.
402
403To start. all the necessary devices must be bound, including bootstd, which
404provides the top-level `struct bootstd_priv` containing optional configuration
405information. The bootstd device is also holds the various lists used while
406scanning. This step is normally handled automatically by driver model, as
407described in `Automatic Devices`_.
408
409Bootdevs are also required, to provide access to the media to use. These are not
410useful by themselves: bootmeths are needed to provide the means of scanning
411those bootdevs. So, all up, we need a single bootstd device, one or more bootdev
412devices and one or more bootmeth devices.
413
414Once these are ready, typically a `bootflow scan` command is issued. This kicks
415of the iteration process, which involves looking through the bootdevs and their
416partitions one by one to find bootflows.
417
418Iteration is kicked off using `bootflow_scan_first()`, which calls
419`bootflow_scan_bootdev()`.
420
421The iterator is set up with `bootflow_iter_init()`. This simply creates an
422empty one with the given flags. Flags are used to control whether each
423iteration is displayed, whether to return iterations even if they did not result
424in a valid bootflow, whether to iterate through just a single bootdev, etc.
425
426Then the ordering of bootdevs is determined, by `bootdev_setup_iter_order()`. By
427default, the bootdevs are used in the order specified by the `boot_targets`
428environment variable (e.g. "mmc2 mmc0 usb"). If that is missing then their
429sequence order is used, as determined by the `/aliases` node, or failing that
430their order in the devicetree. For BOOTSTD_FULL, if there is a `bootdev-order`
431property in the bootstd node, then this is used as a final fallback. In any
432case, the iterator ends up with a `dev_order` array containing the bootdevs that
433are going to be used, with `num_devs` set to the number of bootdevs and
434`cur_dev` starting at 0.
435
Simon Glassafaeb772022-07-30 15:52:35 -0600436Next, the ordering of bootmeths is determined, by `bootmeth_setup_iter_order()`.
Simon Glass83b9be62022-04-24 23:31:26 -0600437By default the ordering is again by sequence number, i.e. the `/aliases` node,
438or failing that the order in the devicetree. But the `bootmeth order` command
439or `bootmeths` environment variable can be used to set up an ordering. If that
440has been done, the ordering is in `struct bootstd_priv`, so that ordering is
441simply copied into the iterator. Either way, the `method_order` array it set up,
Simon Glassafaeb772022-07-30 15:52:35 -0600442along with `num_methods`.
443
444Note that global bootmeths are always put at the end of the ordering. If any are
445present, `cur_method` is set to the first one, so that global bootmeths are done
446first. Once all have been used, these bootmeths are dropped from the iteration.
447When there are no global bootmeths, `cur_method` is set to 0.
Simon Glass83b9be62022-04-24 23:31:26 -0600448
449At this point the iterator is ready to use, with the first bootdev and bootmeth
Simon Glassafaeb772022-07-30 15:52:35 -0600450selected. Most of the other fields are 0. This means that the current partition
451is 0, which is taken to mean the whole device, since partition numbers start at
4521. It also means that `max_part` is 0, i.e. the maximum partition number we know
Simon Glass83b9be62022-04-24 23:31:26 -0600453about is 0, meaning that, as far as we know, there is no partition table on this
454bootdev.
455
456With the iterator ready, `bootflow_scan_bootdev()` checks whether the current
457settings produce a valid bootflow. This is handled by `bootflow_check()`, which
458either returns 0 (if it got something) or an error if not (more on that later).
459If the `BOOTFLOWF_ALL` iterator flag is set, even errors are returned as
460incomplete bootflows, but normally an error results in moving onto the next
461iteration.
462
Simon Glassafaeb772022-07-30 15:52:35 -0600463Note that `bootflow_check()` handles global bootmeths explicitly, but calling
464`bootmeth_get_bootflow()` on each one. The `doing_global` flag indicates when
465the iterator is in that state.
466
Simon Glass83b9be62022-04-24 23:31:26 -0600467The `bootflow_scan_next()` function handles moving onto the next iteration and
468checking it. In fact it sits in a loop doing that repeatedly until it finds
469something it wants to return.
470
471The actual 'moving on' part is implemented in `iter_incr()`. This is a very
472simple function. It increments the first counter. If that hits its maximum, it
473sets it to zero and increments the second counter. You can think of all the
474counters together as a number with three digits which increment in order, with
475the least-sigificant digit on the right, counting like this:
476
477 ======== ======= =======
478 bootdev part method
479 ======== ======= =======
480 0 0 0
481 0 0 1
482 0 0 2
483 0 1 0
484 0 1 1
Simon Glassafaeb772022-07-30 15:52:35 -0600485 0 1 2
Simon Glass83b9be62022-04-24 23:31:26 -0600486 1 0 0
487 1 0 1
Simon Glassafaeb772022-07-30 15:52:35 -0600488 ...
Simon Glass83b9be62022-04-24 23:31:26 -0600489 ======== ======= =======
490
491The maximum value for `method` is `num_methods - 1` so when it exceeds that, it
492goes back to 0 and the next `part` is considered. The maximum value for that is
493`max_part`, which is initially zero for all bootdevs. If we find a partition
494table on that bootdev, `max_part` can be updated during the iteration to a
495higher value - see `bootdev_find_in_blk()` for that, described later. If that
496exceeds its maximum, then the next bootdev is used. In this way, iter_incr()
497works its way through all possibilities, moving forward one each time it is
498called.
499
Simon Glassafaeb772022-07-30 15:52:35 -0600500Note that global bootmeths introduce a subtlety into the above description.
501When `doing_global` is true, the iteration takes place only among the bootmeths,
502i.e. the last column above. The global bootmeths are at the end of the list.
503Assuming that they are entries 3 and 4 in the list, the iteration then looks
504like this:
505
506 ======== ======= ======= =======================================
507 bootdev part method notes
508 ======== ======= ======= =======================================
509 . . 3 doing_global = true, method_count = 5
510 . . 4
511 0 0 0 doing_global = false, method_count = 3
512 0 0 1
513 0 0 2
514 0 1 0
515 0 1 1
516 0 1 2
517 1 0 0
518 1 0 1
519 ...
520 ======== ======= ======= =======================================
521
522The changeover of the value of `doing_global` from true to false is handled in
523`iter_incr()` as well.
524
Simon Glass83b9be62022-04-24 23:31:26 -0600525There is no expectation that iteration will actually finish. Quite often a
526valid bootflow is found early on. With `bootflow scan -b`, that causes the
527bootflow to be immediately booted. Assuming it is successful, the iteration never
528completes.
529
530Also note that the iterator hold the **current** combination being considered.
531So when `iter_incr()` is called, it increments to the next one and returns it,
532the new **current** combination.
533
534Note also the `err` field in `struct bootflow_iter`. This is normally 0 and has
535thus has no effect on `iter_inc()`. But if it is non-zero, signalling an error,
536it indicates to the iterator what it should do when called. It can force moving
537to the next partition, or bootdev, for example. The special values
538`BF_NO_MORE_PARTS` and `BF_NO_MORE_DEVICES` handle this. When `iter_incr` sees
539`BF_NO_MORE_PARTS` it knows that it should immediately move to the next bootdev.
540When it sees `BF_NO_MORE_DEVICES` it knows that there is nothing more it can do
541so it should immediately return. The caller of `iter_incr()` is responsible for
542updating the `err` field, based on the return value it sees.
543
544The above describes the iteration process at a high level. It is basically a
545very simple increment function with a checker called `bootflow_check()` that
546checks the result of each iteration generated, to determine whether it can
547produce a bootflow.
548
549So what happens inside of `bootflow_check()`? It simply calls the uclass
550method `bootdev_get_bootflow()` to ask the bootdev to return a bootflow. It
551passes the iterator to the bootdev method, so that function knows what we are
552talking about. At first, the bootflow is set up in the state `BOOTFLOWST_BASE`,
553with just the `method` and `dev` intiialised. But the bootdev may fill in more,
Simon Glassafaeb772022-07-30 15:52:35 -0600554e.g. updating the state, depending on what it finds. For global bootmeths the
555`bootmeth_get_bootflow()` function is called instead of
556`bootdev_get_bootflow()`.
Simon Glass83b9be62022-04-24 23:31:26 -0600557
Simon Glassafaeb772022-07-30 15:52:35 -0600558Based on what the bootdev or bootmeth responds with, `bootflow_check()` either
Simon Glass83b9be62022-04-24 23:31:26 -0600559returns a valid bootflow, or a partial one with an error. A partial bootflow
560is one that has some fields set up, but did not reach the `BOOTFLOWST_READY`
561state. As noted before, if the `BOOTFLOWF_ALL` iterator flag is set, then all
562bootflows are returned, even partial ones. This can help with debugging.
563
564So at this point you can see that total control over whether a bootflow can
Simon Glassafaeb772022-07-30 15:52:35 -0600565be generated from a particular iteration, or not, rests with the bootdev (or
566global bootmeth). Each one can adopt its own approach.
Simon Glass83b9be62022-04-24 23:31:26 -0600567
568Going down a level, what does the bootdev do in its `get_bootflow()` method?
569Let us consider the MMC bootdev. In that case the call to
570`bootdev_get_bootflow()` ends up in `mmc_get_bootflow()`. It locates the parent
571device of the bootdev, i.e. the `UCLASS_MMC` device itself, then finds the block
572device associated with it. It then calls the helper function
573`bootdev_find_in_blk()` to do all the work. This is common with just about any
574bootdev that is based on a media device.
575
576The `bootdev_find_in_blk()` helper is implemented in the bootdev uclass. It
577names the bootflow and copies the partition number in from the iterator. Then it
578calls the bootmeth device to check if it can support this device. This is
579important since some bootmeths only work with network devices, for example. If
580that check fails, it stops.
581
582Assuming the bootmeth is happy, or at least indicates that it is willing to try
583(by returning 0 from its `check()` method), the next step is to try the
584partition. If that works it tries to detect a file system. If that works then it
585calls the bootmeth device once more, this time to read the bootflow.
586
587Note: At present a filesystem is needed for the bootmeth to be called on block
588devices, simply because we don't have any examples where this is not the case.
589This feature can be added as needed.
590
591If we take the example of the `bootmeth_distro` driver, this call ends up at
592`distro_read_bootflow()`. It has the filesystem ready, so tries various
593filenames to try to find the `extlinux.conf` file, reading it if possible. If
594all goes well the bootflow ends up in the `BOOTFLOWST_READY` state.
595
596At this point, we fall back from the bootmeth driver, to
597`bootdev_find_in_blk()`, then back to `mmc_get_bootflow()`, then to
598`bootdev_get_bootflow()`, then to `bootflow_check()` and finally to its caller,
599either `bootflow_scan_bootdev()` or `bootflow_scan_next()`. In either case,
600the bootflow is returned as the result of this iteration, assuming it made it to
601the `BOOTFLOWST_READY` state.
602
603That is the basic operation of scanning for bootflows. The process of booting a
604bootflow is handled by the bootmeth driver for that bootflow. In the case of
605distro boot, this parses and processes the `extlinux.conf` file that was read.
606See `distro_boot()` for how that works. The processing may involve reading
607additional files, which is handled by the `read_file()` method, which is
608`distro_read_file()` in this case. All bootmethds should support reading files,
609since the bootflow is typically only the basic instructions and does not include
610the operating system itself, ramdisk, device tree, etc.
611
612The vast majority of the bootstd code is concerned with iterating through
613partitions on bootdevs and using bootmethds to find bootflows.
614
615How about bootdevs which are not block devices? They are handled by the same
616methods as above, but with a different implementation. For example, the bootmeth
617for PXE boot (over a network) uses `tftp` to read files rather than `fs_read()`.
618But other than that it is very similar.
619
620
621Tests
622-----
623
624Tests are located in `test/boot` and cover the core functionality as well as
625the commands. All tests use sandbox so can be run on a standard Linux computer
626and in U-Boot's CI.
627
628For testing, a DOS-formatted disk image is used with a single FAT partition on
629it. This is created in `setup_bootflow_image()`, with a canned one from the
630source tree used if it cannot be created (e.g. in CI).
631
632
633Bootflow internals
634------------------
635
636The bootstd device holds a linked list of scanned bootflows as well as the
637currently selected bootdev and bootflow (for use by commands). This is in
638`struct bootstd_priv`.
639
640Each bootdev device has its own `struct bootdev_uc_plat` which holds a
641list of scanned bootflows just for that device.
642
643The bootflow itself is documented in bootflow_h_. It includes various bits of
644information about the bootflow and a buffer to hold the file.
645
646
647Future
648------
649
650Apart from the to-do items below, different types of bootflow files may be
651implemented in future, e.g. Chromium OS support which is currently only
652available as a script in chromebook_coral.
653
654
655To do
656-----
657
658Some things that need to be done to completely replace the distro-boot scripts:
659
660- add bootdev drivers for dhcp, sata, scsi, ide, virtio
661- PXE boot for EFI
662- support for loading U-Boot scripts
663
664Other ideas:
665
666- `bootflow prep` to load everything preparing for boot, so that `bootflow boot`
667 can just do the boot.
668- automatically load kernel, FDT, etc. to suitable addresses so the board does
669 not need to specify things like `pxefile_addr_r`
670
671
Paul Barker6c55d0d2022-07-29 14:31:58 +0100672.. _distro_bootcmd: https://github.com/u-boot/u-boot/blob/master/include/config_distro_bootcmd.h
Simon Glass83b9be62022-04-24 23:31:26 -0600673.. _BootLoaderSpec: http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/
674.. _distro_boot: https://github.com/u-boot/u-boot/blob/master/boot/distro.c
675.. _bootflow_h: https://github.com/u-boot/u-boot/blob/master/include/bootflow.h