]>
Commit | Line | Data |
---|---|---|
c3e270f4 | 1 | --- |
a0fadf66 | 2 | title: Boot Loader Specification |
4cdca0af | 3 | category: Booting |
b41a3f66 | 4 | layout: default |
0aff7b75 | 5 | SPDX-License-Identifier: LGPL-2.1-or-later |
c3e270f4 FB |
6 | --- |
7 | ||
c3c5eeca LP |
8 | # The Boot Loader Specification |
9 | ||
7bb36d2d ZJS |
10 | This document defines a set of file formats and naming conventions that allow |
11 | the boot loader configuration to be shared between multiple operating systems | |
12 | and boot loaders installed on one device. | |
13 | ||
14 | Operating systems cooperatively manage a boot loader configuration directory | |
15 | that contains drop-in files, making multi-boot scenarios easy to support. Boot | |
16 | menu items are defined via a simple format that can be understood by different | |
17 | boot loader implementations, operating systems, and userspace programs. The | |
18 | same scheme can be used to prepare OS media for cases where the firmware | |
19 | includes a boot loader. | |
20 | ||
21 | ## Target audience | |
22 | ||
23 | The target audience for this specification is: | |
c3c5eeca | 24 | |
49d5e4d0 | 25 | * Boot loader developers, to write a boot loader that directly reads its |
7bb36d2d | 26 | configuration from these files |
49d5e4d0 LP |
27 | * Firmware developers, to add generic boot loading support directly to the |
28 | firmware itself | |
7bb36d2d | 29 | * OS installer developers, to create appropriate partitions and set up the |
0f5a416c | 30 | initial boot loader configuration |
7bb36d2d ZJS |
31 | * Distribution developers, to create appropriate configuration snippets when |
32 | installing or updating kernel packages | |
33 | * UI developers, to implement user interfaces that list and select among the | |
34 | available boot options | |
c3c5eeca | 35 | |
7bb36d2d | 36 | ## The boot partition |
c3c5eeca | 37 | |
53c26db4 ZJS |
38 | Everything described below is located on one or two partitions. The boot loader |
39 | or user-space programs reading the boot loader configuration should locate them | |
40 | in the following manner: | |
c3c5eeca | 41 | |
7bb36d2d | 42 | * On disks with an MBR partition table: |
c3c5eeca | 43 | |
53c26db4 ZJS |
44 | * The boot partition — partition with the type ID of 0xEA — shall be used |
45 | for boot loader configuration and entries. | |
c3c5eeca | 46 | |
04c31af4 | 47 | * On disks with GPT (GUID Partition Table) |
7bb36d2d | 48 | |
53c26db4 ZJS |
49 | * The EFI System Partition (ESP for short) — a partition with GPT type GUID |
50 | of `c12a7328-f81f-11d2-ba4b-00a0c93ec93b` — should be used for boot loader | |
51 | configuration and boot entries. | |
7bb36d2d | 52 | |
53c26db4 ZJS |
53 | * Optionally, an Extended Boot Loader Partition (XBOOTLDR partition for |
54 | short) — a partition with GPT type GUID of | |
55 | `bc13c2ff-59e6-4262-a352-b275fd6f7172` — may be used as an additional | |
56 | location for boot loader entries. This partition must be located on the | |
57 | same disk as the ESP. | |
58 | ||
59 | In the text below, `$BOOT` will be used to refer to (the root of) the first of | |
60 | the two partitions (the boot partition on MBR disks and the ESP on GPT disks), | |
61 | and `$XBOOTLDR` will be used to refer to (the root of) the optional second | |
62 | partition. | |
7bb36d2d ZJS |
63 | |
64 | An installer for the operating system should use this logic when selecting or | |
65 | creating partitions: | |
66 | ||
67 | * If `$BOOT` is not found, a new suitably sized partition (let's say 500MB) | |
53c26db4 ZJS |
68 | should be created, matching the characteristics described above. On disks |
69 | with GPT, only the ESP partition without the XBOOTLDR partition should be | |
70 | created. | |
7bb36d2d ZJS |
71 | |
72 | * If the OS is installed on a disk with GPT and the ESP partition is found | |
73 | but is too small, a new suitably sized (let's say 500MB) XBOOTLDR partition | |
53c26db4 ZJS |
74 | shall be created. |
75 | ||
76 | Those file systems shall be determined during _installation time_, and an fstab | |
77 | entry may be created. If only one partition is used, it should be mounted on | |
78 | `/boot/`. If both XBOOTLDR partition and the ESP are used, they should be | |
79 | mounted on `/boot` and `/efi`, or on `/boot` and `/boot/efi`. | |
80 | ||
81 | **Note:** _Those file systems are **shared** among all OS installations on the | |
82 | system. Instead of maintaining one boot partition per installed OS (as `/boot/` | |
83 | was traditionally handled), all installed OSes use the same place for boot-time | |
7bb36d2d | 84 | configuration._ |
c3c5eeca | 85 | |
53c26db4 ZJS |
86 | For systems where the firmware is able to read file systems directly, the ESP |
87 | must — and the XBOOTLDR partition should — be a file system readable by the | |
88 | firmware. For most systems this means VFAT (16 or 32 bit). Applications | |
89 | accessing both partitions should hence not assume that fancier file system | |
7bb36d2d ZJS |
90 | features such as symlinks, hardlinks, access control or case sensitivity are |
91 | supported. | |
92 | ||
93 | ## Boot loader entries | |
c3c5eeca | 94 | |
084a8029 | 95 | This specification defines two types of boot loader entries. The first type is |
7bb36d2d | 96 | text based, very simple, and suitable for a variety of firmware, architecture |
084a8029 | 97 | and image types ("Type #1"). The second type is specific to EFI, but allows |
b2454670 | 98 | single-file images that embed all metadata in the kernel binary itself, which |
084a8029 LP |
99 | is useful to cryptographically sign them as one file for the purpose of |
100 | SecureBoot ("Type #2"). | |
101 | ||
102 | Not all boot loader entries will apply to all systems. For example, Type #1 | |
103 | entries that use the `efi` key and all Type #2 entries only apply to EFI | |
104 | systems. Entries using the `architecture` key might specify an architecture that | |
105 | doesn't match the local one. Boot loaders should ignore all entries that don't | |
106 | match the local platform and what the boot loader can support, and hide them | |
107 | from the user. Only entries matching the feature set of boot loader and system | |
108 | shall be considered and displayed. This allows image builders to put together | |
109 | images that transparently support multiple different architectures. | |
110 | ||
53c26db4 | 111 | Note that the boot partitions are not supposed to be the exclusive territory of |
8384ed93 LP |
112 | this specification. This specification only defines semantics of the `/loader/` |
113 | directory inside the file system (see below), but it doesn't intend to define | |
53c26db4 ZJS |
114 | ownership of the whole file system. Boot loaders, firmware, and other software |
115 | implementing this specification may choose to place other files and directories | |
116 | in the same file system. For example, boot loaders that implement this | |
117 | specification might install their own boot code on the same partition; this is | |
118 | particularly common in the case of the ESP. Implementations of this specification | |
119 | must be able to operate correctly if files or directories other than `/loader/` | |
120 | are found in the top level directory. Implementations that add their own files | |
121 | or directories to the file systems should use well-named directories, to make | |
122 | name collisions between multiple users of the file system unlikely. | |
8384ed93 | 123 | |
084a8029 | 124 | ### Type #1 Boot Loader Specification Entries |
5be7bfbc | 125 | |
53c26db4 | 126 | `$ESP/loader/` is the main directory containing the configuration for the boot |
0f5a416c | 127 | loader. |
49d5e4d0 LP |
128 | |
129 | **Note:** _In all cases the `/loader/` directory should be located directly in | |
53c26db4 ZJS |
130 | the root of the file system. Specifically, the `/loader/` directory should |
131 | **not** be located under the `/EFI/` subdirectory on the ESP._ | |
5be7bfbc | 132 | |
53c26db4 ZJS |
133 | `$BOOT/loader/entries/` and `$XBOOTLDR/loader/entries/` are the directories |
134 | containing the drop-in snippets defining boot entries, one `.conf` file for | |
135 | each boot menu item. Each OS may provide one or more such entries. The boot | |
136 | loader should enumerate both directories and provide a merged list. | |
0f5a416c ZJS |
137 | |
138 | The file name is used for identification of the boot item but shall never be | |
139 | presented to the user in the UI. The file name may be chosen freely but should | |
140 | be unique enough to avoid clashes between OS installations. More specifically, | |
141 | it is suggested to include the `entry-token` (see | |
142 | [kernel-install](https://www.freedesktop.org/software/systemd/man/kernel-install.html)) | |
143 | or machine ID (see | |
144 | [/etc/machine-id](https://www.freedesktop.org/software/systemd/man/machine-id.html)), | |
145 | and the kernel version (as returned by `uname -r`, including the OS | |
146 | identifier), so that the whole filename is | |
147 | `$BOOT/loader/entries/<entry-token-or-machine-id>-<version>.conf`. | |
7bb36d2d ZJS |
148 | |
149 | Example: `$BOOT/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf`. | |
d9067aba LP |
150 | |
151 | In order to maximize compatibility with file system implementations and | |
152 | restricted boot loader environments, and to minimize conflicting character use | |
49d5e4d0 | 153 | with other programs, file names shall be chosen from a restricted character |
7bb36d2d ZJS |
154 | set: ASCII upper and lower case characters, digits, "+", "-", "_" and ".". |
155 | Also, the file names should have a length of at least one and at most 255 | |
156 | characters (including the file name suffix). | |
157 | ||
158 | These configuration snippets shall be UNIX-style text files (i.e. lines | |
159 | separated by a single newline character), in the UTF-8 encoding. The | |
160 | configuration snippets are loosely inspired by Grub1's configuration syntax. | |
161 | Lines beginning with "#" are used for comments and shall be ignored. The first | |
162 | word of a line is used as key and is separated by one or more spaces from the | |
163 | value. | |
164 | ||
165 | #### Type #1 Boot Loader Entry Keys | |
166 | ||
167 | The following keys are recognized: | |
168 | ||
169 | * `title` is a human-readable title for this menu item to be displayed in the | |
170 | boot menu. It is a good idea to initialize this from the `PRETTY_NAME=` of | |
14bacc74 ZJS |
171 | [os-release](https://www.freedesktop.org/software/systemd/man/os-release.html). |
172 | This name should be descriptive and does not have to be unique. If a boot | |
173 | loader discovers two entries with the same title it should show more than | |
174 | just the raw title in the UI, for example by appending the `version` | |
175 | field. This field is optional. | |
7bb36d2d ZJS |
176 | |
177 | Example: `title Fedora 18 (Spherical Cow)` | |
178 | ||
179 | * `version` is a human-readable version for this menu item. This is usually the | |
180 | kernel version and is intended for use by OSes to install multiple kernel | |
2367bdcf ZJS |
181 | versions with the same `title` field. This field is used for sorting entries, |
182 | so that the boot loader can order entries by age or select the newest one | |
7bb36d2d ZJS |
183 | automatically. This field is optional. |
184 | ||
2367bdcf ZJS |
185 | See [Sorting](#sorting) below. |
186 | ||
7bb36d2d ZJS |
187 | Example: `version 3.7.2-201.fc18.x86_64` |
188 | ||
189 | * `machine-id` is the machine ID of the OS. This can be used by boot loaders | |
190 | and applications to filter out boot entries, for example to show only a | |
191 | single newest kernel per OS, to group items by OS, or to filter out the | |
192 | currently booted OS when showing only other installed operating systems. | |
193 | This ID shall be formatted as 32 lower case hexadecimal characters | |
194 | (i.e. without any UUID formatting). This key is optional. | |
195 | ||
196 | Example: `machine-id 4098b3f648d74c13b1f04ccfba7798e8` | |
197 | ||
198 | * `sort-key` is a short string used for sorting entries on display. This should | |
199 | typically be initialized from the `IMAGE_ID=` or `ID=` fields of | |
14bacc74 | 200 | [os-release](https://www.freedesktop.org/software/systemd/man/os-release.html), |
2367bdcf | 201 | possibly with an additional suffix. This field is optional. |
7bb36d2d ZJS |
202 | |
203 | Example: `sort-key fedora` | |
204 | ||
53c26db4 ZJS |
205 | * `linux` is the Linux kernel to spawn and as a path relative to file system |
206 | root. It is recommended that every distribution creates a machine id and | |
207 | version specific subdirectory and places its kernels and initial RAM disk | |
208 | images there. | |
7bb36d2d ZJS |
209 | |
210 | Example: `linux /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux` | |
211 | ||
53c26db4 ZJS |
212 | * `initrd` is the initrd to use when executing the kernel. This key is |
213 | optional. This key may appear more than once in which case all specified | |
214 | images are used, in the order they are listed. | |
7bb36d2d ZJS |
215 | |
216 | Example: `initrd 6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd` | |
217 | ||
53c26db4 ZJS |
218 | * `efi` refers to an arbitrary EFI program. If this key is set, and the system |
219 | is not an EFI system, this entry should be hidden. | |
7bb36d2d | 220 | |
49d5e4d0 LP |
221 | * `options` shall contain kernel parameters to pass to the Linux kernel to |
222 | spawn. This key is optional and may appear more than once in which case all | |
223 | specified parameters are used in the order they are listed. | |
7bb36d2d ZJS |
224 | |
225 | Example: `options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2 quiet` | |
226 | ||
c3c5eeca | 227 | * `devicetree` refers to the binary device tree to use when executing the |
53c26db4 | 228 | kernel. This key is optional. |
7bb36d2d ZJS |
229 | |
230 | Example: `devicetree 6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.armv7hl/tegra20-paz00.dtb` | |
231 | ||
09ee387e | 232 | * `devicetree-overlay` refers to a list of device tree overlays that should be |
49d5e4d0 LP |
233 | applied by the boot loader. Multiple overlays are separated by spaces and |
234 | applied in the same order as they are listed. This key is optional but | |
7bb36d2d ZJS |
235 | depends on the `devicetree` key. |
236 | ||
237 | Example: `devicetree-overlay /6a9857a393724b7a981ebb5b8495b9ea/overlays/overlay_A.dtbo /6a9857a393724b7a981ebb5b8495b9ea/overlays/overlay_B.dtbo` | |
238 | ||
239 | * `architecture` refers to the architecture this entry is for. The argument | |
240 | should be an architecture identifier, using the architecture vocabulary | |
241 | defined by the EFI specification (i.e. `IA32`, `x64`, `IA64`, `ARM`, `AA64`, | |
242 | …). If specified and it does not match the local system architecture this | |
243 | entry should be hidden. The comparison should be done case-insensitively. | |
244 | ||
245 | Example: `architecture aa64` | |
49d5e4d0 LP |
246 | |
247 | Each configuration drop-in snippet must include at least a `linux` or an `efi` | |
7bb36d2d | 248 | key. Here is an example for a complete drop-in file: |
c3c5eeca | 249 | |
6e6b351b | 250 | # /boot/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf |
bdc4c7ac | 251 | title Fedora 19 (Rawhide) |
10119357 | 252 | sort-key fedora |
bdc4c7ac | 253 | machine-id 6a9857a393724b7a981ebb5b8495b9ea |
10119357 | 254 | version 3.8.0-2.fc19.x86_64 |
7bb36d2d | 255 | options root=UUID=6d3376e4-fc93-4509-95ec-a21d68011da2 quiet |
bdc4c7ac LP |
256 | architecture x64 |
257 | linux /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux | |
258 | initrd /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd | |
c3c5eeca | 259 | |
e178b335 LP |
260 | On EFI systems all Linux kernel images should be EFI images. In order to |
261 | increase compatibility with EFI systems it is highly recommended only to | |
262 | install EFI kernel images, even on non-EFI systems, if that's applicable and | |
263 | supported on the specific architecture. | |
264 | ||
265 | Conversely, in order to increase compatibility it is recommended to install | |
266 | generic kernel images that make few assumptions about the firmware they run on, | |
267 | i.e. it is a good idea that both images shipped as UEFI PE images and those | |
268 | which are not don't make unnecessary assumption on the underlying firmware, | |
269 | i.e. don't hard depend on legacy BIOS calls or UEFI boot services. | |
c3c5eeca | 270 | |
0f5a416c ZJS |
271 | When Type #1 configuration snippets refer to other files (for `linux`, |
272 | `initrd`, `efi`, `devicetree`, and `devicetree-overlay`), those files must be | |
53c26db4 ZJS |
273 | located on the same partition, and the paths must be absolute paths relative to |
274 | the root of that file system. The naming of those files can be chosen by the | |
275 | installer. A recommended scheme is described in the next section. | |
0f5a416c ZJS |
276 | |
277 | ### Recommended Directory Layout for Additional Files | |
278 | ||
f79f6856 | 279 | It is recommended to place the kernel and other other files comprising a single |
0f5a416c ZJS |
280 | boot loader entry in a separate directory: |
281 | `/<entry-token-or-machine-id>/<version>/`. This naming scheme uses the same | |
282 | elements as the boot loader configuration snippet, providing the same level of | |
283 | uniqueness. | |
284 | ||
285 | Example: `$BOOT/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux` | |
286 | `$BOOT/6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd` | |
287 | ||
288 | Other naming schemes are possible. In particular, traditionally a flat naming | |
289 | scheme with files in the root directory was used. This is not recommended | |
290 | because it is hard to avoid conflicts in a multi-boot installation. | |
c3c5eeca | 291 | |
7bb36d2d ZJS |
292 | ### Standard-conformance Marker File |
293 | ||
f6ad0282 | 294 | Unfortunately, there are implementations of boot loading infrastructure that |
7bb36d2d ZJS |
295 | are also using the `/loader/entries/` directory, but installing files that do |
296 | not follow this specification. In order to minimize confusion, a boot loader | |
297 | implementation may place the file `/loader/entries.srel` next to the | |
298 | `/loader/entries/` directory containing the ASCII string `type1` (followed by a | |
299 | UNIX newline). Tools that need to determine whether an existing directory | |
300 | implements the semantics described here may check for this file and contents: | |
301 | if it exists and contains the mentioned string, it shall assume a | |
302 | standards-compliant implementation is in place. If it exists but contains a | |
303 | different string it shall assume other semantics are implemented. If the file | |
304 | does not exist, no assumptions should be made. | |
f6ad0282 | 305 | |
084a8029 LP |
306 | ### Type #2 EFI Unified Kernel Images |
307 | ||
308 | A unified kernel image is a single EFI PE executable combining an EFI stub | |
309 | loader, a kernel image, an initramfs image, and the kernel command line. See | |
310 | the description of the `--uefi` option in | |
e2285c57 | 311 | [dracut(8)](https://man7.org/linux/man-pages/man8/dracut.8.html). Such unified |
53c26db4 ZJS |
312 | images are installed in the`$BOOT/EFI/Linux/` and `$XBOOTLDR/EFI/Linux/` |
313 | directories and must have the extension `.efi`. | |
314 | Support for images of this type is of course specific to systems with EFI | |
315 | firmware. Ignore this section if you work on systems not supporting EFI. | |
5be7bfbc | 316 | |
d9067aba | 317 | Type #2 file names should be chosen from the same restricted character set as |
7bb36d2d ZJS |
318 | Type #1 described above (but with the file name suffix of `.efi` instead of |
319 | `.conf`). | |
d9067aba | 320 | |
084a8029 | 321 | Images of this type have the advantage that all metadata and payload that makes |
7bb36d2d | 322 | up the boot entry is contained in a single PE file that can be signed |
084a8029 | 323 | cryptographically as one for the purpose of EFI SecureBoot. |
5be7bfbc ZJS |
324 | |
325 | A valid unified kernel image must contain two PE sections: | |
326 | ||
7bb36d2d | 327 | * `.cmdline` section with the kernel command line, |
49d5e4d0 LP |
328 | * `.osrel` section with an embedded copy of the |
329 | [os-release](https://www.freedesktop.org/software/systemd/man/os-release.html) | |
7bb36d2d | 330 | file describing the image. |
889cb0ab | 331 | |
7bb36d2d ZJS |
332 | The `PRETTY_NAME=` and `VERSION_ID=` fields in the embedded `os-release` file |
333 | are used the same as `title` and `version` in the Type #1 entries. The | |
334 | `.cmdline` section is used instead of the `options` field. `linux` and `initrd` | |
335 | fields are not necessary, and there is no counterpart for the `machine-id` | |
336 | field. | |
5be7bfbc | 337 | |
084a8029 | 338 | On EFI, any such images shall be added to the list of valid boot entries. |
5be7bfbc ZJS |
339 | |
340 | ### Additional notes | |
341 | ||
49d5e4d0 LP |
342 | Note that these configurations snippets do not need to be the only |
343 | configuration source for a boot loader. It may extend this list of entries with | |
344 | additional items from other configuration files (for example its own native | |
345 | configuration files) or automatically detected other entries without explicit | |
346 | configuration. | |
5be7bfbc | 347 | |
49d5e4d0 LP |
348 | To make this explicitly clear: this specification is designed with "free" |
349 | operating systems in mind, starting Windows or macOS is out of focus with these | |
350 | configuration snippets, use boot-loader specific solutions for that. In the | |
351 | text above, if we say "OS" we hence imply "free", i.e. primarily Linux (though | |
352 | this could be easily be extended to the BSDs and whatnot). | |
c3c5eeca | 353 | |
49d5e4d0 LP |
354 | Note that all paths used in the configuration snippets use a Unix-style "/" as |
355 | path separator. This needs to be converted to an EFI-style "\\" separator in | |
356 | EFI boot loaders. | |
c3c5eeca LP |
357 | |
358 | ||
7bb36d2d | 359 | ## Locating boot entries |
c3c5eeca | 360 | |
53c26db4 ZJS |
361 | A _boot loader_ locates `$BOOT` and `$XBOOTLDR`, then simply reads all the |
362 | files `$BOOT/loader/entries/*.conf` and `$XBOOTLDR/loader/entries/*.conf`, and | |
363 | populates its boot menu. On EFI, it then extends this with any unified kernel | |
364 | images found in `$BOOT/EFI/Linux/*.efi` and `$XBOOTLDR/EFI/Linux/*.efi`. It may | |
365 | also add additional entries, for example a "Reboot into firmware" option. | |
366 | Optionally it may sort the menu based on the `sort-key`, `machine-id` and | |
367 | `version` fields, and possibly others. It uses the file name to identify | |
368 | specific items, for example in case it supports storing away default entry | |
369 | information somewhere. A boot loader should generally not modify these files. | |
084a8029 LP |
370 | |
371 | For "Boot Loader Specification Entries" (Type #1), the _kernel package | |
53c26db4 ZJS |
372 | installer_ installs the kernel and initrd images to `$XBOOTLDR` (if used) or |
373 | `$BOOT`. It is recommended to place these files in a vendor and OS and | |
374 | installation specific directory. It then generates a configuration snippet, | |
375 | placing it in `$BOOT/loader/entries/xyz.conf`, with "xyz" as concatenation of | |
376 | machine id and version information (see above). The files created by a kernel | |
377 | package are tied to the kernel package and should be removed along with it. | |
084a8029 LP |
378 | |
379 | For "EFI Unified Kernel Images" (Type #2), the vendor or kernel package | |
7bb36d2d ZJS |
380 | installer should create the combined image and drop it into |
381 | `$BOOT/EFI/Linux/`. This file is also tied to the kernel package and should be | |
382 | removed along with it. | |
c3c5eeca | 383 | |
49d5e4d0 | 384 | A _UI application_ intended to show available boot options shall operate |
7bb36d2d ZJS |
385 | similarly to a boot loader, but might apply additional filters, for example by |
386 | filtering the booted OS via the machine ID, or by suppressing all but the | |
49d5e4d0 | 387 | newest kernel versions. |
c3c5eeca | 388 | |
49d5e4d0 | 389 | An _OS installer_ picks the right place for `$BOOT` as defined above (possibly |
7bb36d2d ZJS |
390 | creating a partition and file system for it) and creates the `/loader/entries/` |
391 | directory in it. It then installs an appropriate boot loader that can read | |
392 | these snippets. Finally, it installs one or more kernel packages. | |
393 | ||
db82e667 ZJS |
394 | ## Boot counting |
395 | ||
396 | The main idea is that when boot entries are initially installed, they are | |
397 | marked as "indeterminate" and assigned a number of boot attempts. Each time the | |
398 | boot loader tries to boot an entry, it decreases this count by one. If the | |
399 | operating system considers the boot as successful, it removes the counter | |
400 | altogether and the entry becomes "good". Otherwise, once the assigned number of | |
401 | boots is exhausted, the entry is marked as "bad". | |
402 | ||
403 | Which boots are "successful" is determined by the operating system. systemd | |
404 | provides a generic mechanism that can be extended with arbitrary checks and | |
74223cbe | 405 | actions, see [Automatic Boot Assessment](AUTOMATIC_BOOT_ASSESSMENT.md), but the |
db82e667 ZJS |
406 | boot counting mechanism described in this specifaction can also be used with |
407 | other implementations. | |
408 | ||
409 | The boot counting data is stored in the name of the boot loader entry. A boot | |
410 | loader entry file name may contain a plus (`+`) followed by a number. This may | |
411 | optionally be followed by a minus (`-`) followed by a second number. The dot | |
412 | (`.`) and file name suffix (`conf` of `efi`) must immediately follow. Boot | |
413 | counting is enabled for entries which match this pattern. | |
414 | ||
415 | The first number is the "tries left" counter signifying how many attempts to boot | |
416 | this entry shall still be made. The second number is the "tries done" counter, | |
417 | showing how many failed attempts to boot it have already been made. Each time | |
418 | a boot loader entry marked this way is booted, the first counter is decremented, | |
419 | and the second one incremented. (If the second counter is missing, | |
420 | then it is assumed to be equivalent to zero.) If the "tries left" counter is | |
421 | above zero the entry is still considered "indeterminate". A boot entry with the | |
422 | "tries left" counter at zero is considered "bad". | |
423 | ||
424 | If the boot attempt completed successfully the entry's counters are removed | |
425 | from the name (entry state becomes "good"), thus turning off boot counting for | |
426 | this entry. | |
427 | ||
2367bdcf ZJS |
428 | ## Sorting |
429 | ||
430 | The boot loader menu should generally show entries in some order meaningful to | |
431 | the user. The `title` key is free-form and not suitable to be used as the | |
432 | primary sorting key. Instead, the boot loader should use the following rules: | |
db82e667 ZJS |
433 | |
434 | 1. Entries which are subject to boot counting and are marked as "bad", should | |
435 | be sorted later than all other entries. Entries which are marked as | |
436 | "indeterminate" or "good" (or were not subject to boot counting at all), | |
437 | are thus sorted earlier. | |
438 | ||
439 | 2. If `sort-key` is set on both entries, use in order of priority, | |
440 | the `sort-key` (A-Z, increasing [alphanumerical order](#alphanumerical-order)), | |
441 | `machine-id` (A-Z, increasing alphanumerical order), | |
442 | and `version` keys (decreasing [version order](#version-order)). | |
443 | ||
444 | 3. If `sort-key` is set on one entry, it sorts earlier. | |
445 | ||
446 | 4. At the end, if necessary, when `sort-key` is not set or those fields are not | |
447 | set or are all equal, the boot loader should sort using the file name of the | |
448 | entry (decreasing version sort), with the suffix removed. | |
2367bdcf ZJS |
449 | |
450 | **Note:** _This description assumes that the boot loader shows entries in a | |
451 | traditional menu, with newest and "best" entries at the top, thus entries with | |
452 | a higher version number are sorter *earlier*. The boot loader is free to | |
453 | use a different direction (or none at all) during display._ | |
454 | ||
db82e667 ZJS |
455 | **Note:** _The boot loader should allow booting "bad" entries, e.g. in case no |
456 | other entries are left or they are unusable for other reasons. It may | |
457 | deemphasize or hide such entries by default._ | |
458 | ||
459 | **Note:** _"Bad" boot entries have a suffix of "+0-`n`", where `n` is the | |
460 | number of failed boot attempts. Removal of the suffix is not necessary for | |
461 | comparisons described by the last point above. In the unlikely scenario that we | |
462 | have multiple such boot entries that differ only by the boot counting data, we | |
463 | would sort them by `n`._ | |
464 | ||
2367bdcf ZJS |
465 | ### Alphanumerical order |
466 | ||
467 | Free-form strings and machine IDs should be compared using a method equivalent | |
468 | to [strcmp(3)](https://man7.org/linux/man-pages/man3/strcmp.3.html) on their | |
f79f6856 | 469 | UTF-8 representations. If just one of the strings is unspecified or empty, it |
2367bdcf ZJS |
470 | compares lower. If both strings are unspecified or empty, they compare equal. |
471 | ||
472 | ### Version order | |
473 | ||
474 | The following method should be used to compare version strings. The algorithm | |
475 | is based on rpm's `rpmvercmp()`, but not identical. | |
476 | ||
477 | ASCII letters (`a-z`, `A-Z`) and digits (`0-9`) form alphanumerical components of the version. | |
478 | Minus (`-`) separates the version and release parts. | |
479 | Dot (`.`) separates parts of version or release. | |
480 | Tilde (`~`) is a prefix that always compares lower. | |
481 | Caret (`^`) is a prefix that always compares higher. | |
482 | ||
483 | Both strings are compared from the beginning until the end, or until the | |
484 | strings are found to compare as different. In a loop: | |
485 | 1. Any characters which are outside of the set of listed above (`a-z`, `A-Z`, `0-9`, `-`, `.`, `~`, `^`) | |
486 | are skipped in both strings. In particular, this means that non-ASCII characters | |
487 | that are Unicode digits or letters are skipped too. | |
488 | 2. If one of the strings has ended: if the other string hasn't, the string that | |
489 | has remaining characters compares higher. Otherwise, the strings compare | |
490 | equal. | |
491 | 3. If the remaining part of one of strings starts with `~`: | |
492 | if other remaining part does not start with `~`, | |
493 | the string with `~` compares lower. Otherwise, both tilde characters are skipped. | |
494 | 4. The check from point 2. is repeated here. | |
495 | 5. If the remaining part of one of strings starts with `-`: | |
496 | if the other remaining part does not start with `-`, | |
497 | the string with `-` compares lower. Otherwise, both minus characters are skipped. | |
498 | 6. If the remaining part of one of strings starts with `^`: | |
499 | if the other remaining part does not start with `^`, | |
500 | the string with `^` compares higher. Otherwise, both caret characters are skipped. | |
501 | 6. If the remaining part of one of strings starts with `.`: | |
502 | if the other remaining part does not start with `.`, | |
503 | the string with `.` compares lower. Otherwise, both dot characters are skipped. | |
504 | 7. If either of the remaining parts starts with a digit, numerical prefixes are | |
505 | compared numerically. Any leading zeroes are skipped. | |
506 | The numerical prefixes (until the first non-digit character) are evaluated as numbers. | |
507 | If one of the prefixes is empty, it evaluates as 0. | |
508 | If the numbers are different, the string with the bigger number compares higher. | |
509 | Otherwise, the comparison continues at the following characters at point 1. | |
510 | 8. Leading alphabetical prefixes are compared alphabetically. | |
511 | The substrings are compared letter-by-letter. | |
512 | If both letters are the same, the comparison continues with the next letter. | |
513 | Capital letters compare lower than lower-case letters (`A < a`). | |
514 | When the end of one substring has been reached (a non-letter character or the end | |
515 | of the whole string), if the other substring has remaining letters, it compares higher. | |
516 | Otherwise, the comparison continues at the following characters at point 1. | |
517 | ||
518 | Examples (with '' meaning the empty string): | |
519 | ||
520 | * `11 == 11` | |
521 | * `systemd-123 == systemd-123` | |
522 | * `bar-123 < foo-123` | |
523 | * `123a > 123` | |
524 | * `123.a > 123` | |
525 | * `123.a < 123.b` | |
526 | * `123a > 123.a` | |
527 | * `11α == 11β` | |
528 | * `A < a` | |
529 | * '' < `0` | |
530 | * `0.` > `0` | |
531 | * `0.0` > `0` | |
532 | * `0` < `~` | |
533 | * '' < `~` | |
534 | ||
535 | Note: [systemd-analyze](https://www.freedesktop.org/software/systemd/man/systemd-analyze.html) | |
536 | implements this version comparison algorithm as | |
537 | ``` | |
538 | systemd-analyze compare-versions <version-a> <version-b> | |
539 | ``` | |
7bb36d2d ZJS |
540 | |
541 | ## Additional discussion | |
542 | ||
543 | ### Why is there a need for this specification? | |
544 | ||
545 | This specification brings the following advantages: | |
546 | ||
547 | * Installation of new boot entries is more robust, as no explicit rewriting of | |
548 | configuration files is required. | |
549 | ||
550 | * It allows an out-of-the-box boot experience on any platform without the need | |
551 | of traditional firmware mechanisms (e.g. BIOS calls, UEFI Boot Services). | |
552 | ||
553 | * It improves dual-boot scenarios. Without cooperation, multiple Linux | |
554 | installations tend to fight over which boot loader becomes the primary one in | |
555 | possession of the MBR or the boot partition, and only that one installation | |
556 | can then update the boot loader configuration. Other Linux installs have to | |
557 | be manually configured to never touch the MBR and instead install a | |
558 | chain-loaded boot loader in their own partition headers. In this new scheme | |
559 | all installations share a loader directory and no manual configuration has to | |
560 | take place. All participants implicitly cooperate due to removal of name | |
561 | collisions and can install/remove their own boot menu entries without | |
562 | interfering with the entries of other installed operating systems. | |
563 | ||
564 | * Drop-in directories are now pretty ubiquitous on Linux as an easy way to | |
565 | extend configuration without having to edit, regenerate or manipulate | |
566 | configuration files. For the sake of uniformity, we should do the same for | |
567 | the boot menu. | |
568 | ||
569 | * Userspace code can sanely parse boot loader configuration which is essential | |
570 | with modern firmware which does not necessarily initialize USB keyboards | |
571 | during boot, which makes boot menus hard to reach for the user. If userspace | |
572 | code can parse the boot loader configuration too, UI can be written that | |
573 | select a boot menu item to boot into before rebooting the machine, thus not | |
574 | requiring interactivity during early boot. | |
575 | ||
576 | * To unify and thus simplify configuration of the various boot loaders, which | |
577 | makes configuration of the boot loading process easier for users, | |
578 | administrators, and developers alike. | |
579 | ||
580 | * For boot loaders with configuration _scripts_ such as grub2, adopting this | |
581 | spec allows for mostly static scripts that are generated only once at first | |
582 | installation, but then do not need to be updated anymore as that is done via | |
583 | drop-in files exclusively. | |
584 | ||
585 | ### Why not simply rely on the EFI boot menu logic? | |
c3c5eeca | 586 | |
7bb36d2d ZJS |
587 | EFI is not ubiquitous, especially not in embedded systems. But even on systems |
588 | with EFI, which provides a boot options logic that can offer similar | |
f79f6856 | 589 | functionality, this specification is still needed for the following reasons: |
c3c5eeca | 590 | |
7bb36d2d ZJS |
591 | * The various EFI implementations implement the boot order/boot item logic to |
592 | different levels. Some firmware implementations do not offer a boot menu at | |
593 | all and instead unconditionally follow the EFI boot order, booting the first | |
594 | item that is working. | |
595 | ||
596 | * If the firmware setup is used to reset data, usually all EFI boot entries | |
597 | are lost, making the system entirely unbootable, as the firmware setups | |
598 | generally do not offer a UI to define additional boot items. By placing the | |
599 | menu item information on disk, it is always available, even if the firmware | |
600 | configuration is lost. | |
601 | ||
602 | * Harddisk images should be movable between machines and be bootable without | |
f79f6856 | 603 | requiring firmware configuration. This also requires that the list |
7bb36d2d ZJS |
604 | of boot options is defined on disk, and not in EFI variables alone. |
605 | ||
606 | * EFI is not universal yet (especially on non-x86 platforms), this | |
607 | specification is useful both for EFI and non-EFI boot loaders. | |
608 | ||
609 | * Many EFI systems disable USB support during early boot to optimize boot | |
610 | times, thus making keyboard input unavailable in the EFI menu. It is thus | |
611 | useful if the OS UI has a standardized way to discover available boot options | |
612 | which can be booted to. | |
613 | ||
f79f6856 | 614 | ### Why is the version comparison logic so complicated? |
2367bdcf ZJS |
615 | |
616 | The `sort-key` allows us to group entries by "operating system", e.g. all | |
617 | versions of Fedora together, no matter if they identify themselves as "Fedora | |
618 | Workstation" or "Fedora Rawhide (prerelease)". The `sort-key` was introduced | |
619 | only recently, so we need to provide a meaningful order for entries both with | |
620 | and without it. Since it is a new concept, it is assumed that entries with | |
621 | `sort-key` are newer. | |
622 | ||
623 | In a traditional menu with entries displayed vertically, we want names to be | |
624 | sorter alpabetically (CentOS, Debian, Fedora, OpenSUSE, …), it would be strange | |
625 | to have them in reverse order. But when multiple kernels are available for the | |
626 | same installation, we want to display the latest kernel with highest priority, | |
627 | i.e. earlier in the list. | |
628 | ||
db82e667 ZJS |
629 | ### Why do you use file renames to store the counter? Why not a regular file? |
630 | ||
631 | Mainly two reasons: it's relatively likely that renames can be implemented | |
632 | atomically even in simpler file systems, as renaming generally avoids | |
633 | allocating or releasing data blocks. Writing to file contents has a much bigger | |
634 | chance to be result in incomplete or corrupt data. Moreover renaming has the | |
635 | benefit that the boot count metadata is directly attached to the boot loader | |
636 | entry file, and thus the lifecycle of the metadata and the entry itself are | |
637 | bound together. This means no additional clean-up needs to take place to drop | |
638 | the boot loader counting information for an entry when it is removed. | |
639 | ||
640 | ### Why not use EFI variables for storing the boot counter? | |
641 | ||
642 | The memory chips used to back the persistent EFI variables are generally not of | |
643 | the highest quality, hence shouldn't be written to more than necessary. This | |
644 | means we can't really use it for changes made regularly during boot, but should | |
645 | use it only for seldom-made configuration changes. | |
646 | ||
7bb36d2d | 647 | ### Out of Focus |
c3c5eeca | 648 | |
7957e55d | 649 | There are a couple of items that are out of focus for this specification: |
c3c5eeca | 650 | |
49d5e4d0 LP |
651 | * If userspace can figure out the available boot options, then this is only |
652 | useful so much: we'd still need to come up with a way how userspace could | |
653 | communicate to the boot loader the default boot loader entry temporarily or | |
654 | persistently. Defining a common scheme for this is certainly a good idea, but | |
655 | out of focus for this specification. | |
7bb36d2d | 656 | |
49d5e4d0 LP |
657 | * This specification is just about "Free" Operating systems. Hooking in other |
658 | operating systems (like Windows and macOS) into the boot menu is a different | |
659 | story and should probably happen outside of this specification. For example, | |
660 | boot loaders might choose to detect other available OSes dynamically at | |
661 | runtime without explicit configuration (like `systemd-boot` does it), or via | |
662 | native configuration (for example via explicit Grub2 configuration generated | |
663 | once at installation). | |
7bb36d2d | 664 | |
49d5e4d0 LP |
665 | * This specification leaves undefined what to do about systems which are |
666 | upgraded from an OS that does not implement this specification. As the | |
667 | previous boot loader logic was largely handled by in distribution-specific | |
668 | ways we probably should leave the upgrade path (and whether there actually is | |
669 | one) to the distributions. The simplest solution might be to simply continue | |
670 | with the old scheme for old installations and use this new scheme only for | |
671 | new installations. | |
c3c5eeca | 672 | |
0f5a416c ZJS |
673 | * Referencing kernels or initrds on other partitions other than the partition |
674 | containing the Type #1 boot loader entry. This is by design, as specifying | |
675 | other partitions or devices would require a non-trivial language for denoting | |
676 | device paths. In particular this means that on non-EFI systems configuration | |
677 | snippets following this specification cannot be used to spawn other operating | |
678 | systems (such as Windows). | |
679 | ||
c3c5eeca LP |
680 | |
681 | ## Links | |
682 | ||
b0cda241 | 683 | [GUID Partition Table](https://en.wikipedia.org/wiki/GUID_Partition_Table)<br> |
5c90c67a BF |
684 | [Boot Loader Interface](BOOT_LOADER_INTERFACE.md)<br> |
685 | [Discoverable Partitions Specification](DISCOVERABLE_PARTITIONS.md)<br> | |
a43d2229 LP |
686 | [`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/systemd-boot.html)<br> |
687 | [`bootctl(1)`](https://www.freedesktop.org/software/systemd/man/bootctl.html)<br> | |
688 | [`systemd-gpt-auto-generator(8)`](https://www.freedesktop.org/software/systemd/man/systemd-gpt-auto-generator.html) |