1.. 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 24distro_bootcmd_ for details. This is done because U-Boot has no native support 25for 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 35Finally, standard boot supports the operation of :doc:`vbe`. 36 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 55which to load devicetree files. The details are described in distro_bootcmd_. 56 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 with the boot flag set, 75then provides a list of these for consideration. 76 77Some bootdevs are not visible until a bus is enumerated, e.g. flash sticks 78attached via USB. To deal with this, each bootdev has an associated 'hunter' 79which can hunt for bootdevs of a particular uclass type. For example, the SCSI 80bootdev scans the SCSI bus looking for devices, creating a bootdev for each 81Logical Unit Number (LUN) that it finds. 82 83 84Bootmeth 85-------- 86 87Once the list of filesystems is provided, how does U-Boot find the bootflow 88files in these filesystems. That is the job of bootmeth. Each boot method has 89its own way of doing this. 90 91For example, the distro bootmeth simply looks through the provided filesystem 92for a file called `extlinux/extlinux.conf`. This files constitutes a bootflow. 93If the distro bootmeth is used on multiple partitions it may produce multiple 94bootflows. 95 96Note: it is possible to have a bootmeth that uses a partition or a whole device 97directly, but it is more common to use a filesystem. 98 99Note that some bootmeths are 'global', meaning that they select the bootdev 100themselves. Examples include VBE and EFI boot manager. In this case, they 101provide a `read_bootflow()` method which checks whatever bootdevs it likes, then 102returns the bootflow, if found. Some of these bootmeths may be very slow, if 103they scan a lot of devices. 104 105 106Boot process 107------------ 108 109U-Boot tries to use the 'lazy init' approach whereever possible and distro boot 110is no exception. The algorithm is:: 111 112 while (get next bootdev) 113 while (get next bootmeth) 114 while (get next bootflow) 115 try to boot it 116 117So U-Boot works its way through the bootdevs, trying each bootmeth in turn to 118obtain bootflows, until it either boots or exhausts the available options. 119 120Instead of 500 lines of #defines and a 4KB boot script, all that is needed is 121the following command:: 122 123 bootflow scan -lb 124 125which scans for available bootflows, optionally listing each find it finds (-l) 126and trying to boot it (-b). 127 128When global bootmeths are available, these are typically checked before the 129above bootdev scanning. 130 131 132Controlling ordering 133-------------------- 134 135Several options are available to control the ordering of boot scanning: 136 137 138boot_targets 139~~~~~~~~~~~~ 140 141This environment variable can be used to control the list of bootdevs searched 142and their ordering, for example:: 143 144 setenv boot_targets "mmc0 mmc1 usb pxe" 145 146Entries may be removed or re-ordered in this list to affect the boot order. If 147the variable is empty, the default ordering is used, based on the priority of 148bootdevs and their sequence numbers. 149 150 151bootmeths 152~~~~~~~~~ 153 154This environment variable can be used to control the list of bootmeths used and 155their ordering for example:: 156 157 setenv bootmeths "extlinux efi" 158 159Entries may be removed or re-ordered in this list to affect the order the 160bootmeths are tried on each bootdev. If the variable is empty, the default 161ordering is used, based on the bootmeth sequence numbers, which can be 162controlled by aliases. 163 164The :ref:`usage/cmd/bootmeth:bootmeth command` (`bootmeth order`) operates in 165the same way as setting this variable. 166 167 168Bootdev uclass 169-------------- 170 171The bootdev uclass provides an simple API call to obtain a bootflows from a 172device:: 173 174 int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, 175 struct bootflow *bflow); 176 177This takes a iterator which indicates the bootdev, partition and bootmeth to 178use. It returns a bootflow. This is the core of the bootdev implementation. The 179bootdev drivers that implement this differ depending on the media they are 180reading from, but each is responsible for returning a valid bootflow if 181available. 182 183A helper called `bootdev_find_in_blk()` makes it fairly easy to implement this 184function for each media device uclass, in a few lines of code. For many types 185ot bootdevs, the `get_bootflow` member can be NULL, indicating that the default 186handler is used. This is called `default_get_bootflow()` and it only works with 187block devices. 188 189 190Bootdev drivers 191--------------- 192 193A bootdev driver is typically fairly simple. Here is one for mmc:: 194 195 static int mmc_bootdev_bind(struct udevice *dev) 196 { 197 struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); 198 199 ucp->prio = BOOTDEVP_2_INTERNAL_FAST; 200 201 return 0; 202 } 203 204 struct bootdev_ops mmc_bootdev_ops = { 205 }; 206 207 static const struct udevice_id mmc_bootdev_ids[] = { 208 { .compatible = "u-boot,bootdev-mmc" }, 209 { } 210 }; 211 212 U_BOOT_DRIVER(mmc_bootdev) = { 213 .name = "mmc_bootdev", 214 .id = UCLASS_BOOTDEV, 215 .ops = &mmc_bootdev_ops, 216 .bind = mmc_bootdev_bind, 217 .of_match = mmc_bootdev_ids, 218 }; 219 220You may notice that the `get_bootflow` memory is not provided, so is NULL. This 221means that `default_get_bootflow()` is used. This simply obtains the 222block device and calls a bootdev helper function to do the rest. The 223implementation of `bootdev_find_in_blk()` checks the partition table, and 224attempts to read a file from a filesystem on the partition number given by the 225`@iter->part` parameter. If there are any bootable partitions in the table, 226then only bootable partitions are considered. 227 228Each bootdev has a priority, which indicates the order in which it is used, 229if `boot_targets` is not used. Faster bootdevs are used first, since they are 230more likely to be able to boot the device quickly. 231 232 233Environment Variables 234--------------------- 235 236Various environment variables are used by standard boot. These allow the board 237to control where things are placed when booting the OS. You should ensure that 238your boards sets values for these. 239 240fdtfile 241 Name of the flattened device tree (FDT) file to load, e.g. 242 "rockchip/rk3399-rockpro64.dtb" 243 244fdtaddr_addr_r 245 Address at which to load the FDT, e.g. 0x01f00000 246 247fdtoverlay_addr_r (needed if overlays are used) 248 Address at which to load the overlay for the FDT, e.g. 0x02000000 249 250kernel_addr_r 251 Address at which to load the kernel, e.g. 0x02080000 252 253kernel_comp_addr_r 254 Address to which to decompress the kernel, e.g. 0x08000000 255 256kernel_comp_size 257 Size of available space for decompressed kernel, e.g. 0x2000000 258 259pxefile_addr_r 260 Address at which to load the PXE file, e.g. 0x00600000 261 262ramdisk_addr_r 263 Address at which to load the ramdisk, e.g. 0x06000000 264 265scriptaddr 266 Address at which to load the U-Boot script, e.g. 0x00500000 267 268script_offset_f 269 SPI flash offset from which to load the U-Boot script, e.g. 0xffe000 270 271script_size_f 272 Size of the script to load, e.g. 0x2000 273 274Some variables are set by script bootmeth: 275 276devtype 277 Device type being used for boot, e.g. mmc 278 279devnum 280 Device number being used for boot, e.g. 1 281 282distro_bootpart 283 Partition being used for boot, e.g. 2 284 285prefix 286 Directory containing the script 287 288mmc_bootdev 289 Device number being used for boot (e.g. 1). This is only used by MMC on 290 sunxi boards. 291 292 293Device hierarchy 294---------------- 295 296A bootdev device is a child of the media device. In this example, you can see 297that the bootdev is a sibling of the block device and both are children of 298media device:: 299 300 mmc 0 [ + ] bcm2835-sdhost | |-- mmc@7e202000 301 blk 0 [ + ] mmc_blk | | |-- mmc@7e202000.blk 302 bootdev 0 [ ] mmc_bootdev | | `-- mmc@7e202000.bootdev 303 mmc 1 [ + ] sdhci-bcm2835 | |-- sdhci@7e300000 304 blk 1 [ ] mmc_blk | | |-- sdhci@7e300000.blk 305 bootdev 1 [ ] mmc_bootdev | | `-- sdhci@7e300000.bootdev 306 307The bootdev device is typically created automatically in the media uclass' 308`post_bind()` method by calling `bootdev_setup_for_dev()` or 309`bootdev_setup_sibling_blk()`. The code typically something like this:: 310 311 /* dev is the Ethernet device */ 312 ret = bootdev_setup_for_dev(dev, "eth_bootdev"); 313 if (ret) 314 return log_msg_ret("bootdev", ret); 315 316or:: 317 318 /* blk is the block device (child of MMC device) 319 ret = bootdev_setup_sibling_blk(blk, "mmc_bootdev"); 320 if (ret) 321 return log_msg_ret("bootdev", ret); 322 323 324Here, `eth_bootdev` is the name of the Ethernet bootdev driver and `dev` 325is the ethernet device. This function is safe to call even if standard boot is 326not enabled, since it does nothing in that case. It can be added to all uclasses 327which implement suitable media. 328 329 330The bootstd device 331------------------ 332 333Standard boot requires a single instance of the bootstd device to make things 334work. This includes global information about the state of standard boot. See 335`struct bootstd_priv` for this structure, accessed with `bootstd_get_priv()`. 336 337Within the devicetree, if you add bootmeth devices, they should be children of 338the bootstd device. See `arch/sandbox/dts/test.dts` for an example of this. 339 340 341.. _`Automatic Devices`: 342 343Automatic devices 344----------------- 345 346It is possible to define all the required devices in the devicetree manually, 347but it is not necessary. The bootstd uclass includes a `dm_scan_other()` 348function which creates the bootstd device if not found. If no bootmeth devices 349are found at all, it creates one for each available bootmeth driver. 350 351If your devicetree has any bootmeth device it must have all of them that you 352want to use, since no bootmeth devices will be created automatically in that 353case. 354 355 356Using devicetree 357---------------- 358 359If a bootdev is complicated or needs configuration information, it can be 360added to the devicetree as a child of the media device. For example, imagine a 361bootdev which reads a bootflow from SPI flash. The devicetree fragment might 362look like this:: 363 364 spi@0 { 365 flash@0 { 366 reg = <0>; 367 compatible = "spansion,m25p16", "jedec,spi-nor"; 368 spi-max-frequency = <40000000>; 369 370 bootdev { 371 compatible = "u-boot,sf-bootdev"; 372 offset = <0x2000>; 373 size = <0x1000>; 374 }; 375 }; 376 }; 377 378The `sf-bootdev` driver can implement a way to read from the SPI flash, using 379the offset and size provided, and return that bootflow file back to the caller. 380When distro boot wants to read the kernel it calls distro_getfile() which must 381provide a way to read from the SPI flash. See `distro_boot()` at distro_boot_ 382for more details. 383 384Of course this is all internal to U-Boot. All the distro sees is another way 385to boot. 386 387 388Configuration 389------------- 390 391Standard boot is enabled with `CONFIG_BOOTSTD`. Each bootmeth has its own CONFIG 392option also. For example, `CONFIG_BOOTMETH_EXTLINUX` enables support for 393booting from a disk using an `extlinux.conf` file. 394 395To enable all feature sof standard boot, use `CONFIG_BOOTSTD_FULL`. This 396includes the full set of commands, more error messages when things go wrong and 397bootmeth ordering with the bootmeths environment variable. 398 399You should probably also enable `CONFIG_BOOTSTD_DEFAULTS`, which provides 400several filesystem and network features (if `CONFIG_NET` is enabled) so that 401a good selection of boot options is available. 402 403 404Available bootmeth drivers 405-------------------------- 406 407Bootmeth drivers are provided for: 408 409 - extlinux / syslinux boot from a disk 410 - extlinux boot from a network (PXE) 411 - U-Boot scripts from disk, network or SPI flash 412 - EFI boot using bootefi from disk 413 - VBE 414 - EFI boot using boot manager 415 416 417Command interface 418----------------- 419 420Three commands are available: 421 422`bootdev` 423 Allows listing of available bootdevs, selecting a particular one and 424 getting information about it. See :doc:`../usage/cmd/bootdev` 425 426`bootflow` 427 Allows scanning one or more bootdevs for bootflows, listing available 428 bootflows, selecting one, obtaining information about it and booting it. 429 See :doc:`../usage/cmd/bootflow` 430 431`bootmeth` 432 Allow listing of available bootmethds and setting the order in which they 433 are tried. See :doc:`../usage/cmd/bootmeth` 434 435.. _BootflowStates: 436 437Bootflow states 438--------------- 439 440Here is a list of states that a bootflow can be in: 441 442======= ======================================================================= 443State Meaning 444======= ======================================================================= 445base Starting-out state, indicates that no media/partition was found. For an 446 SD card socket it may indicate that the card is not inserted. 447media Media was found (e.g. SD card is inserted) but no partition information 448 was found. It might lack a partition table or have a read error. 449part Partition was found but a filesystem could not be read. This could be 450 because the partition does not hold a filesystem or the filesystem is 451 very corrupted. 452fs Filesystem was found but the file could not be read. It could be 453 missing or in the wrong subdirectory. 454file File was found and its size detected, but it could not be read. This 455 could indicate filesystem corruption. 456ready File was loaded and is ready for use. In this state the bootflow is 457 ready to be booted. 458======= ======================================================================= 459 460 461Theory of operation 462------------------- 463 464This describes how standard boot progresses through to booting an operating 465system. 466 467To start. all the necessary devices must be bound, including bootstd, which 468provides the top-level `struct bootstd_priv` containing optional configuration 469information. The bootstd device is also holds the various lists used while 470scanning. This step is normally handled automatically by driver model, as 471described in `Automatic Devices`_. 472 473Bootdevs are also required, to provide access to the media to use. These are not 474useful by themselves: bootmeths are needed to provide the means of scanning 475those bootdevs. So, all up, we need a single bootstd device, one or more bootdev 476devices and one or more bootmeth devices. 477 478Once these are ready, typically a `bootflow scan` command is issued. This kicks 479of the iteration process, which involves hunting for bootdevs and looking 480through the bootdevs and their partitions one by one to find bootflows. 481 482Iteration is kicked off using `bootflow_scan_first()`. 483 484The iterator is set up with `bootflow_iter_init()`. This simply creates an 485empty one with the given flags. Flags are used to control whether each 486iteration is displayed, whether to return iterations even if they did not result 487in a valid bootflow, whether to iterate through just a single bootdev, etc. 488 489Then the iterator is set up to according to the parameters given: 490 491- When `dev` is provided, then a single bootdev is scanned. In this case, 492 `BOOTFLOWIF_SKIP_GLOBAL` and `BOOTFLOWIF_SINGLE_DEV` are set. No hunters are 493 used in this case 494 495- Otherwise, when `label` is provided, then a single label or named bootdev is 496 scanned. In this case `BOOTFLOWIF_SKIP_GLOBAL` is set and there are three 497 options (with an effect on the `iter_incr()` function described later): 498 499 - If `label` indicates a numeric bootdev number (e.g. "2") then 500 `BOOTFLOW_METHF_SINGLE_DEV` is set. In this case, moving to the next bootdev 501 simple stops, since there is only one. No hunters are used. 502 - If `label` indicates a particular media device (e.g. "mmc1") then 503 `BOOTFLOWIF_SINGLE_MEDIA` is set. In this case, moving to the next bootdev 504 processes just the children of the media device. Hunters are used, in this 505 example just the "mmc" hunter. 506 - If `label` indicates a media uclass (e.g. "mmc") then 507 `BOOTFLOWIF_SINGLE_UCLASS` is set. In this case, all bootdevs in that uclass 508 are used. Hunters are used, in this example just the "mmc" hunter 509 510- Otherwise, none of the above flags is set and iteration is set up to work 511 through `boot_targets` environment variable (or `bootdev-order` device tree 512 property) in order, running the relevant hunter first. In this case 513 `cur_label` is used to indicate the label being processed. If there is no list 514 of labels, then all bootdevs are processed in order of priority, running the 515 hunters as it goes. 516 517With the above it is therefore possible to iterate in a variety of ways. 518 519No attempt is made to determine the ordering of bootdevs, since this cannot be 520known in advance if we are using the hunters. Any hunter might discover a new 521bootdev and disturb the original ordering. 522 523Next, the ordering of bootmeths is determined, by `bootmeth_setup_iter_order()`. 524By default the ordering is again by sequence number, i.e. the `/aliases` node, 525or failing that the order in the devicetree. But the `bootmeth order` command 526or `bootmeths` environment variable can be used to set up an ordering. If that 527has been done, the ordering is in `struct bootstd_priv`, so that ordering is 528simply copied into the iterator. Either way, the `method_order` array it set up, 529along with `num_methods`. 530 531Note that global bootmeths are always put at the end of the ordering. If any are 532present, `cur_method` is set to the first one, so that global bootmeths are done 533first. Once all have been used, these bootmeths are dropped from the iteration. 534When there are no global bootmeths, `cur_method` is set to 0. 535 536At this point the iterator is ready to use, with the first bootmeth selected. 537Most of the other fields are 0. This means that the current partition 538is 0, which is taken to mean the whole device, since partition numbers start at 5391. It also means that `max_part` is 0, i.e. the maximum partition number we know 540about is 0, meaning that, as far as we know, there is no partition table on this 541bootdev. 542 543With the iterator ready, `bootflow_scan_first()` checks whether the current 544settings produce a valid bootflow. This is handled by `bootflow_check()`, which 545either returns 0 (if it got something) or an error if not (more on that later). 546If the `BOOTFLOWIF_ALL` iterator flag is set, even errors are returned as 547incomplete bootflows, but normally an error results in moving onto the next 548iteration. 549 550Note that `bootflow_check()` handles global bootmeths explicitly, by calling 551`bootmeth_get_bootflow()` on each one. The `doing_global` flag indicates when 552the iterator is in that state. 553 554The `bootflow_scan_next()` function handles moving onto the next iteration and 555checking it. In fact it sits in a loop doing that repeatedly until it finds 556something it wants to return. 557 558The actual 'moving on' part is implemented in `iter_incr()`. This is a fairly 559simple function. It increments the first counter. If that hits its maximum, it 560sets it to zero and increments the second counter. You can think of all the 561counters together as a number with three digits which increment in order, with 562the least-sigificant digit on the right, counting like this: 563 564 ======== ======= ======= 565 bootdev part method 566 ======== ======= ======= 567 0 0 0 568 0 0 1 569 0 0 2 570 0 1 0 571 0 1 1 572 0 1 2 573 1 0 0 574 1 0 1 575 ... 576 ======== ======= ======= 577 578The maximum value for `method` is `num_methods - 1` so when it exceeds that, it 579goes back to 0 and the next `part` is considered. The maximum value for that is 580`max_part`, which is initially zero for all bootdevs. If we find a partition 581table on that bootdev, `max_part` can be updated during the iteration to a 582higher value - see `bootdev_find_in_blk()` for that, described later. If that 583exceeds its maximum, then the next bootdev is used. In this way, iter_incr() 584works its way through all possibilities, moving forward one each time it is 585called. 586 587Note that global bootmeths introduce a subtlety into the above description. 588When `doing_global` is true, the iteration takes place only among the bootmeths, 589i.e. the last column above. The global bootmeths are at the end of the list. 590Assuming that they are entries 3 and 4 in the list, the iteration then looks 591like this: 592 593 ======== ======= ======= ======================================= 594 bootdev part method notes 595 ======== ======= ======= ======================================= 596 . . 3 doing_global = true, method_count = 5 597 . . 4 598 0 0 0 doing_global = false, method_count = 3 599 0 0 1 600 0 0 2 601 0 1 0 602 0 1 1 603 0 1 2 604 1 0 0 605 1 0 1 606 ... 607 ======== ======= ======= ======================================= 608 609The changeover of the value of `doing_global` from true to false is handled in 610`iter_incr()` as well. 611 612Note that the value in the `bootdev` column above is not actually stored - it is 613just for illustration. In practice, `iter_incr()` uses the flags to determine 614whether to move to the next bootdev in the uclass, the next child of the media 615device, the next label, or the next priority level, depending on the flag 616settings (see `BOOTFLOW_METHF_SINGLE_DEV`, etc. above). 617 618There is no expectation that iteration will actually finish. Quite often a 619valid bootflow is found early on. With `bootflow scan -b`, that causes the 620bootflow to be immediately booted. Assuming it is successful, the iteration never 621completes. 622 623Also note that the iterator hold the **current** combination being considered. 624So when `iter_incr()` is called, it increments to the next one and returns it, 625the new **current** combination. 626 627Note also the `err` field in `struct bootflow_iter`. This is normally 0 and has 628thus has no effect on `iter_inc()`. But if it is non-zero, signalling an error, 629it indicates to the iterator what it should do when called. It can force moving 630to the next partition, or bootdev, for example. The special values 631`BF_NO_MORE_PARTS` and `BF_NO_MORE_DEVICES` handle this. When `iter_incr` sees 632`BF_NO_MORE_PARTS` it knows that it should immediately move to the next bootdev. 633When it sees `BF_NO_MORE_DEVICES` it knows that there is nothing more it can do 634so it should immediately return. The caller of `iter_incr()` is responsible for 635updating the `err` field, based on the return value it sees. 636 637The above describes the iteration process at a high level. It is basically a 638very simple increment function with a checker called `bootflow_check()` that 639checks the result of each iteration generated, to determine whether it can 640produce a bootflow. 641 642So what happens inside of `bootflow_check()`? It simply calls the uclass 643method `bootdev_get_bootflow()` to ask the bootdev to return a bootflow. It 644passes the iterator to the bootdev method, so that function knows what we are 645talking about. At first, the bootflow is set up in the state `BOOTFLOWST_BASE`, 646with just the `method` and `dev` intiialised. But the bootdev may fill in more, 647e.g. updating the state, depending on what it finds. For global bootmeths the 648`bootmeth_get_bootflow()` function is called instead of 649`bootdev_get_bootflow()`. 650 651Based on what the bootdev or bootmeth responds with, `bootflow_check()` either 652returns a valid bootflow, or a partial one with an error. A partial bootflow 653is one that has some fields set up, but did not reach the `BOOTFLOWST_READY` 654state. As noted before, if the `BOOTFLOWIF_ALL` iterator flag is set, then all 655bootflows are returned, even partial ones. This can help with debugging. 656 657So at this point you can see that total control over whether a bootflow can 658be generated from a particular iteration, or not, rests with the bootdev (or 659global bootmeth). Each one can adopt its own approach. 660 661Going down a level, what does the bootdev do in its `get_bootflow()` method? 662Let us consider the MMC bootdev. In that case the call to 663`bootdev_get_bootflow()` ends up in `default_get_bootflow()`. It locates the 664parent device of the bootdev, i.e. the `UCLASS_MMC` device itself, then finds 665the block device associated with it. It then calls the helper function 666`bootdev_find_in_blk()` to do all the work. This is common with just about any 667bootdev that is based on a media device. 668 669The `bootdev_find_in_blk()` helper is implemented in the bootdev uclass. It 670names the bootflow and copies the partition number in from the iterator. Then it 671calls the bootmeth device to check if it can support this device. This is 672important since some bootmeths only work with network devices, for example. If 673that check fails, it stops. 674 675Assuming the bootmeth is happy, or at least indicates that it is willing to try 676(by returning 0 from its `check()` method), the next step is to try the 677partition. If that works it tries to detect a file system. If that works then it 678calls the bootmeth device once more, this time to read the bootflow. 679 680Note: At present a filesystem is needed for the bootmeth to be called on block 681devices, simply because we don't have any examples where this is not the case. 682This feature can be added as needed. Note that sandbox is a special case, since 683in that case the host filesystem can be accessed even though the block device 684is NULL. 685 686If we take the example of the `bootmeth_extlinux` driver, this call ends up at 687`extlinux_read_bootflow()`. It has the filesystem ready, so tries various 688filenames to try to find the `extlinux.conf` file, reading it if possible. If 689all goes well the bootflow ends up in the `BOOTFLOWST_READY` state. 690 691At this point, we fall back from the bootmeth driver, to 692`bootdev_find_in_blk()`, then back to `default_get_bootflow()`, then to 693`bootdev_get_bootflow()`, then to `bootflow_check()` and finally to its caller, 694either `bootflow_scan_first()` or `bootflow_scan_next()`. In either case, 695the bootflow is returned as the result of this iteration, assuming it made it to 696the `BOOTFLOWST_READY` state. 697 698That is the basic operation of scanning for bootflows. The process of booting a 699bootflow is handled by the bootmeth driver for that bootflow. In the case of 700extlinux boot, this parses and processes the `extlinux.conf` file that was read. 701See `extlinux_boot()` for how that works. The processing may involve reading 702additional files, which is handled by the `read_file()` method, which is 703`extlinux_read_file()` in this case. All bootmethds should support reading 704files, since the bootflow is typically only the basic instructions and does not 705include the operating system itself, ramdisk, device tree, etc. 706 707The vast majority of the bootstd code is concerned with iterating through 708partitions on bootdevs and using bootmethds to find bootflows. 709 710How about bootdevs which are not block devices? They are handled by the same 711methods as above, but with a different implementation. For example, the bootmeth 712for PXE boot (over a network) uses `tftp` to read files rather than `fs_read()`. 713But other than that it is very similar. 714 715 716Tests 717----- 718 719Tests are located in `test/boot` and cover the core functionality as well as 720the commands. All tests use sandbox so can be run on a standard Linux computer 721and in U-Boot's CI. 722 723For testing, a DOS-formatted disk image is used with a FAT partition on it and 724a second unused partition. This is created in `setup_bootflow_image()`, with a 725canned one from the source tree used if it cannot be created (e.g. in CI). 726 727 728Bootflow internals 729------------------ 730 731The bootstd device holds a linked list of scanned bootflows as well as the 732currently selected bootdev and bootflow (for use by commands). This is in 733`struct bootstd_priv`. 734 735Each bootdev device has its own `struct bootdev_uc_plat` which holds a 736list of scanned bootflows just for that device. 737 738The bootflow itself is documented in bootflow_h_. It includes various bits of 739information about the bootflow and a buffer to hold the file. 740 741 742Future 743------ 744 745Apart from the to-do items below, different types of bootflow files may be 746implemented in future, e.g. Chromium OS support which is currently only 747available as a script in chromebook_coral. 748 749 750To do 751----- 752 753Some things that need to be done to completely replace the distro-boot scripts: 754 755- add bootdev drivers for dhcp, sata, scsi, ide, virtio 756- PXE boot for EFI 757- support for loading U-Boot scripts 758 759Other ideas: 760 761- `bootflow prep` to load everything preparing for boot, so that `bootflow boot` 762 can just do the boot. 763- automatically load kernel, FDT, etc. to suitable addresses so the board does 764 not need to specify things like `pxefile_addr_r` 765 766 767.. _distro_bootcmd: https://github.com/u-boot/u-boot/blob/master/include/config_distro_bootcmd.h 768.. _BootLoaderSpec: http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/ 769.. _distro_boot: https://github.com/u-boot/u-boot/blob/master/boot/distro.c 770.. _bootflow_h: https://github.com/u-boot/u-boot/blob/master/include/bootflow.h 771