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