mirror of
https://github.com/edera-dev/sprout.git
synced 2026-11-04 18:42:21 +00:00
docs(config): add CONFIG.md and move the configuration reference out of the README (#119)
CONFIG.md documents every section of sprout.toml, the command line options, BLS support and strict mode. The README keeps the overview and minimal examples and links to it. Adds an update-config-docs skill to keep the reference in sync with the code.
This commit is contained in:
5 files changed
+670
-195
No files matched your search
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
name: update-config-docs
|
||||||
|
description: Bring CONFIG.md back in line with the code. Use after changing anything in crates/config, the command line options, loader.conf handling, strict mode, or autoconfiguration, or when asked to check that CONFIG.md is accurate.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Update CONFIG.md
|
||||||
|
|
||||||
|
`CONFIG.md` is the reference for `sprout.toml`, the command line options, BLS support and strict mode.
|
||||||
|
The README only links to it, so a setting that is missing from CONFIG.md is undocumented.
|
||||||
|
|
||||||
|
## 1. Find what changed
|
||||||
|
|
||||||
|
Start from the diff, or from the whole config surface if there is none:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git diff main -- crates/config crates/boot/src/options.rs crates/boot/src/config crates/boot/src/autoconfigure crates/bls
|
||||||
|
```
|
||||||
|
|
||||||
|
The sources of truth, and the section of CONFIG.md each one feeds:
|
||||||
|
|
||||||
|
| Source | Section |
|
||||||
|
|-----------------------------------------------------------|-------------------------------------------|
|
||||||
|
| `crates/config/src/lib.rs` | file at a glance, `options` |
|
||||||
|
| `crates/config/src/drivers.rs` | `drivers` |
|
||||||
|
| `crates/config/src/extractors*` | `extractors` |
|
||||||
|
| `crates/config/src/actions*` | `actions` |
|
||||||
|
| `crates/config/src/entries.rs` | `entries` |
|
||||||
|
| `crates/config/src/generators*` | `generators`, `variants`, `exclude` |
|
||||||
|
| `crates/config/src/phases.rs` | `phases` |
|
||||||
|
| `crates/boot/src/options.rs` | command line options |
|
||||||
|
| `crates/boot/src/main.rs` | boot order, defaults, timeout and default entry order, strict mode |
|
||||||
|
| `crates/boot/src/autoconfigure*` | autoconfiguration |
|
||||||
|
| `crates/boot/src/generators/bls.rs`, `crates/bls` | BLS values, boot counting, `loader.conf` |
|
||||||
|
|
||||||
|
## 2. Check each key
|
||||||
|
|
||||||
|
For every struct field in `crates/config`, CONFIG.md needs its TOML name (look at `#[serde(rename)]`, as
|
||||||
|
most multi-word keys use dashes), its type, its default, and what it does. Read the code that uses it in
|
||||||
|
`crates/boot`, not only the doc comment, because the behavior is what the reader depends on.
|
||||||
|
|
||||||
|
Look for the usual drift:
|
||||||
|
|
||||||
|
- a field added, renamed or removed
|
||||||
|
- a default that changed (`#[serde(default = ...)]`, the `Default` impls, constants such as
|
||||||
|
`DEFAULT_MENU_TIMEOUT_SECONDS`)
|
||||||
|
- a new BLS value set with `context.set`, or a new option in `SproutOptions`
|
||||||
|
- a new row to add to, or remove from, the strict mode table
|
||||||
|
- a changed order: the default entry sources, the menu timeout sources, or the phases
|
||||||
|
- `LATEST_VERSION` changing, which the intro and `version` text must follow
|
||||||
|
|
||||||
|
Don't document what you can't confirm in the code. If a behavior is unclear, read the function that
|
||||||
|
implements it.
|
||||||
|
|
||||||
|
## 3. Write the change
|
||||||
|
|
||||||
|
- Keep each section's shape: a short explanation, a TOML example, then a table of keys.
|
||||||
|
- Examples must parse. Check that every key in one exists and is spelled the way serde expects.
|
||||||
|
- Update the table of contents if you add or rename a heading.
|
||||||
|
- Keep README.md short. It gets the feature list and the minimal examples, and CONFIG.md gets everything else.
|
||||||
|
- Don't duplicate the strict mode table or the default entry order anywhere else.
|
||||||
|
|
||||||
|
## 4. Write like a person
|
||||||
|
|
||||||
|
Plain sentences, said once. Skip these:
|
||||||
|
|
||||||
|
- filler like "robust", "seamless", "powerful", "leverage", "ensure", "note that", "it's important to"
|
||||||
|
- groups of three added for rhythm, and a summary sentence at the end of every section
|
||||||
|
- bullet lists for what a sentence says better, and bold used as decoration
|
||||||
|
- em dashes (use a comma, colon or parentheses)
|
||||||
|
|
||||||
|
Say what a setting does and what happens when it's unset or wrong. Name real things (`bootctl`, `PCR 12`,
|
||||||
|
`\EFI\Linux`) instead of describing them.
|
||||||
|
|
||||||
|
## 5. Verify
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build --target x86_64-unknown-uefi
|
||||||
|
cargo build --target aarch64-unknown-uefi
|
||||||
|
cargo fmt --all --check
|
||||||
|
```
|
||||||
|
|
||||||
|
Then re-read the diff of CONFIG.md against the code once more for any key whose name or default you
|
||||||
|
touched. If the change was only to docs, skip the builds.
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
Sprout is a programmable UEFI bootloader written in Rust, for `x86_64` and `aarch64`. It is a `no_std` workspace
|
Sprout is a programmable UEFI bootloader written in Rust, for `x86_64` and `aarch64`. It is a `no_std` workspace
|
||||||
built for the `*-unknown-uefi` targets, so it cannot be run or tested like a normal binary.
|
built for the `*-unknown-uefi` targets, so it cannot be run or tested like a normal binary.
|
||||||
See [README.md](README.md) for the configuration format and features.
|
See [README.md](README.md) for features and [CONFIG.md](CONFIG.md) for the configuration format.
|
||||||
|
After changing configuration, run the `update-config-docs` skill to keep CONFIG.md accurate.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,576 @@
|
|||||||
|
# Configuring Sprout
|
||||||
|
|
||||||
|
Sprout reads a TOML file, `\sprout.toml`, from the root of the EFI partition it was loaded from. This page
|
||||||
|
covers everything that file can hold, the command line options that override it, and the BLS behavior that
|
||||||
|
sits next to it. For installing Sprout, see the [setup guides](./docs/setup).
|
||||||
|
|
||||||
|
- [Command line options](#command-line-options)
|
||||||
|
- [The file at a glance](#the-file-at-a-glance)
|
||||||
|
- [Values](#values)
|
||||||
|
- [`options`](#options)
|
||||||
|
- [`menu-styles`](#menu-styles)
|
||||||
|
- [`drivers`](#drivers)
|
||||||
|
- [`extractors`](#extractors)
|
||||||
|
- [`actions`](#actions)
|
||||||
|
- [`entries`](#entries)
|
||||||
|
- [`generators`](#generators)
|
||||||
|
- [`phases`](#phases)
|
||||||
|
- [Autoconfiguration](#autoconfiguration)
|
||||||
|
- [Bootloader Specification support](#bootloader-specification-support)
|
||||||
|
- [Strict mode](#strict-mode)
|
||||||
|
|
||||||
|
Sprout reads the file once at startup. A key it doesn't know is ignored with a warning that names the key, so
|
||||||
|
a typo shows up in the boot log instead of silently doing nothing. A `version` other than `1` stops Sprout.
|
||||||
|
|
||||||
|
## Command line options
|
||||||
|
|
||||||
|
These are passed to `sprout.efi` as load options, which is how GRUB or `efibootmgr` hand them over. They
|
||||||
|
override the matching setting in the file.
|
||||||
|
|
||||||
|
| Option | What it does |
|
||||||
|
|---------------------------|-----------------------------------------------------------------------------|
|
||||||
|
| `--config=PATH` | Load a configuration file other than `\sprout.toml`. |
|
||||||
|
| `--autoconfigure` | Skip the configuration file and build one from what Sprout finds. |
|
||||||
|
| `--boot=ENTRY` | Boot an entry without showing the menu. See [entries](#entries) for matching. |
|
||||||
|
| `--force-menu` | Show the menu even when `--boot` picked an entry. |
|
||||||
|
| `--menu-style=STYLE` | `basic`, `simple` or `graphical`. |
|
||||||
|
| `--menu-timeout=SECONDS` | How long the menu waits before booting the default entry. |
|
||||||
|
| `--retain-boot-console` | Don't clear the screen before handing off to the entry. |
|
||||||
|
| `--bls-strict-mode` | Turn on [strict mode](#strict-mode). |
|
||||||
|
| `--help` | Print the options. |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Boot a specific configuration file.
|
||||||
|
$ sprout.efi --config=\path\to\config.toml
|
||||||
|
# Boot "Boot Xen" at once, but only show the menu if it can't be found.
|
||||||
|
$ sprout.efi --boot="Boot Xen"
|
||||||
|
# Show the graphical menu for 10 seconds.
|
||||||
|
$ sprout.efi --menu-style=graphical --menu-timeout=10
|
||||||
|
```
|
||||||
|
|
||||||
|
An argument Sprout can't parse is dropped with a warning and the rest are used, since a typo in a boot
|
||||||
|
entry shouldn't leave a machine unbootable.
|
||||||
|
|
||||||
|
## The file at a glance
|
||||||
|
|
||||||
|
Every section is optional. An empty file is a valid configuration that has no entries.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
version = 1
|
||||||
|
|
||||||
|
[options] # settings for Sprout itself
|
||||||
|
[menu-styles.x] # settings for a style of menu
|
||||||
|
[values] # named strings for use anywhere with $name
|
||||||
|
[drivers.x] # EFI drivers to load
|
||||||
|
[extractors.x] # values worked out at boot
|
||||||
|
[actions.x] # things Sprout can do
|
||||||
|
[entries.x] # items in the boot menu
|
||||||
|
[generators.x] # makes entries from data
|
||||||
|
[[phases.early]] # actions to run at set points
|
||||||
|
```
|
||||||
|
|
||||||
|
The pieces fit together like this: an **entry** is a menu item that runs **actions**; an action is configured
|
||||||
|
with strings that can contain **values**; values come from the `[values]` table, from **extractors**, and
|
||||||
|
from **generators**. **Drivers** run first so the filesystems the rest of the file points at exist.
|
||||||
|
|
||||||
|
Order at boot:
|
||||||
|
|
||||||
|
1. `phases.early`
|
||||||
|
2. drivers load
|
||||||
|
3. autoconfiguration, if enabled
|
||||||
|
4. extractors run
|
||||||
|
5. `phases.startup`
|
||||||
|
6. entries and generators produce the menu
|
||||||
|
7. an entry is chosen
|
||||||
|
8. `phases.late`, then the entry's actions
|
||||||
|
|
||||||
|
## Values
|
||||||
|
|
||||||
|
A value is a named string. Anywhere a string is accepted in an entry, action, driver path or phase, `$name`
|
||||||
|
is replaced with the value called `name`.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[values]
|
||||||
|
root-options = "root=/dev/sda2 ro"
|
||||||
|
kernel = "\\vmlinuz"
|
||||||
|
|
||||||
|
[actions.boot]
|
||||||
|
chainload.path = "$kernel"
|
||||||
|
chainload.options = ["$root-options", "quiet"]
|
||||||
|
```
|
||||||
|
|
||||||
|
Some details that matter in practice:
|
||||||
|
|
||||||
|
- Values can refer to other values. Sprout keeps substituting until nothing changes, so
|
||||||
|
`a = "$b"`, `b = "x"` gives `x` for both. A value that never settles, such as one that contains itself,
|
||||||
|
is an error once it hits an iteration or length limit.
|
||||||
|
- When two keys share a prefix, the longer one wins, so `$kernel-options` is never read as `$kernel` plus
|
||||||
|
`-options`.
|
||||||
|
- A `$name` that has no value is left in the string as written.
|
||||||
|
- Values are layered. A key in a generator or entry overrides the same key set globally, and only for that
|
||||||
|
entry. From weakest to strongest: `[values]`, extractor results, generator values (and `variants`), then the
|
||||||
|
`values` of the entry itself.
|
||||||
|
- Windows-style paths need doubled backslashes in TOML strings: `"\\EFI\\Linux"`. Literal strings
|
||||||
|
(`'\EFI\Linux'`) work too.
|
||||||
|
|
||||||
|
## `options`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[options]
|
||||||
|
default-entry = "boot-linux"
|
||||||
|
menu-timeout = 5
|
||||||
|
menu-style = "graphical"
|
||||||
|
autoconfigure = false
|
||||||
|
bls-strict-mode = false
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Type | Default | Meaning |
|
||||||
|
|-------------------|---------|----------|-------------------------------------------------------------------------|
|
||||||
|
| `default-entry` | string | none | The entry that is selected first, and booted when the timeout ends. Without it, the first entry in the menu is. |
|
||||||
|
| `menu-timeout` | integer | see below | Seconds to show the menu before booting the default entry. |
|
||||||
|
| `menu-style` | string | `simple` | `basic` prints entries and takes a number. `simple` is a full-screen list moved with the arrow keys. `graphical` is a menu drawn on the screen (the mouse is off unless you enable it, see [`menu-styles`](#menu-styles)). |
|
||||||
|
| `autoconfigure` | boolean | `false` | Add entries for what Sprout finds. See [autoconfiguration](#autoconfiguration). |
|
||||||
|
| `bls-strict-mode` | boolean | `false` | See [strict mode](#strict-mode). |
|
||||||
|
|
||||||
|
When `menu-timeout` is not set anywhere, the menu shows for 10 seconds, or is hidden in strict mode. The
|
||||||
|
sources are ranked in [The bootloader interface](#the-bootloader-interface).
|
||||||
|
|
||||||
|
## `menu-styles`
|
||||||
|
|
||||||
|
Settings for a particular menu style. Only the graphical menu has any.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[menu-styles.graphical]
|
||||||
|
enable-mouse = true
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Type | Default | Meaning |
|
||||||
|
|----------------|---------|---------|----------------------------------------------------------------------|
|
||||||
|
| `enable-mouse` | boolean | `false` | Select entries with the mouse and show the cursor. Without it, or when the firmware has no pointing device, the menu takes the keyboard only. |
|
||||||
|
|
||||||
|
## `drivers`
|
||||||
|
|
||||||
|
Drivers are EFI executables that add features, most often a filesystem driver for something the firmware
|
||||||
|
can't read, such as ext4. Each is started once and expected to return. Afterwards Sprout reconnects every
|
||||||
|
controller so the new filesystems appear. Drivers have no defined load order.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[drivers.ext4]
|
||||||
|
path = "\\sprout\\drivers\\ext4.efi"
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Meaning |
|
||||||
|
|--------|--------------------------------------------------------|
|
||||||
|
| `path` | Path to the driver image. Required. Can use values. |
|
||||||
|
|
||||||
|
The name (`ext4` above) is only for error messages and doesn't have to match the file.
|
||||||
|
|
||||||
|
## `extractors`
|
||||||
|
|
||||||
|
An extractor works out a value when Sprout boots, so a configuration doesn't need to hardcode where things
|
||||||
|
are. The name of the extractor is the name of the value it sets.
|
||||||
|
|
||||||
|
There is one kind, `filesystem-device-match`, which finds a filesystem and returns its device root. The
|
||||||
|
result has a trailing slash, so you append a path to it directly: `$boot\\vmlinuz`.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[extractors.boot]
|
||||||
|
filesystem-device-match.has-label = "BOOT"
|
||||||
|
filesystem-device-match.fallback = "PciRoot(0x0)/Pci(0x1,0x1)/Sata(0,0,0)/HD(1,GPT,c2a4f1b6-0000-0000-0000-000000000000)/"
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Meaning |
|
||||||
|
|--------------------------|----------------------------------------------------------------------|
|
||||||
|
| `has-label` | The filesystem volume label equals this. |
|
||||||
|
| `has-item` | This file or directory exists on the filesystem. |
|
||||||
|
| `has-partition-uuid` | The unique GUID of the partition. |
|
||||||
|
| `has-partition-type-uuid`| The partition type GUID, such as the one for XBOOTLDR. |
|
||||||
|
| `fallback` | What to use when no filesystem matches. Without it, no match is an error. |
|
||||||
|
|
||||||
|
Every criterion you give must match, and you must give at least one. The first matching filesystem wins.
|
||||||
|
`has-label` and `has-item` can use values.
|
||||||
|
|
||||||
|
## `actions`
|
||||||
|
|
||||||
|
An action is a named, configured piece of work. Entries and phases refer to actions by name, and an action
|
||||||
|
can be used by as many of them as you like.
|
||||||
|
|
||||||
|
Each action sets exactly one of `chainload`, `print` or `edera`. If you set more than one Sprout warns and
|
||||||
|
uses the first of them in that order.
|
||||||
|
|
||||||
|
### `chainload`
|
||||||
|
|
||||||
|
Loads and starts another EFI image. That covers Linux through its EFI stub, Windows, and any other EFI
|
||||||
|
application. If the image returns, Sprout returns to its own flow.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[actions.boot-linux]
|
||||||
|
chainload.path = "\\vmlinuz"
|
||||||
|
chainload.options = ["root=/dev/sda1", "quiet"]
|
||||||
|
chainload.linux-initrd = "\\initrd"
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Type | Meaning |
|
||||||
|
|----------------------|-----------------|----------------------------------------------------------------------|
|
||||||
|
| `path` | string | The image to start. Required. |
|
||||||
|
| `options` | list of strings | Joined with spaces and given to the image as its command line. |
|
||||||
|
| `linux-initrd` | string | One initrd, handed to the Linux EFI stub through the initrd media loader. |
|
||||||
|
| `linux-initrd-chain` | list of strings | Several initrds, concatenated in order into one. Can't be used together with `linux-initrd`. |
|
||||||
|
| `devicetree` | string | A flattened devicetree to install until the image returns. |
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- `linux-initrd` is better than an `initrd=` option, because it doesn't depend on the stub resolving a path.
|
||||||
|
- Entries in `linux-initrd-chain` that are empty after substitution are skipped, which is what makes a
|
||||||
|
chain with spare slots safe.
|
||||||
|
- The devicetree is ignored with a warning when Secure Boot is on, as Sprout can't verify it. If it can't be
|
||||||
|
installed, Sprout warns and boots without it, unless [strict mode](#strict-mode) is on.
|
||||||
|
- When the image is a Windows boot manager or another non-Linux image, leave the initrd keys out.
|
||||||
|
|
||||||
|
### `print`
|
||||||
|
|
||||||
|
Writes a line to the console. It's mostly for phases, such as a message while drivers load.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[actions.hello]
|
||||||
|
print.text = "Booting $version"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `edera`
|
||||||
|
|
||||||
|
Boots the Edera hypervisor and its root operating system, as an extension of the Xen EFI stub. Sprout hands
|
||||||
|
the Xen config, dom0 kernel and optional initrd to Xen as media loaders, then starts Xen.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[actions.edera]
|
||||||
|
edera.xen = "\\EFI\\edera\\xen.efi"
|
||||||
|
edera.kernel = "\\EFI\\edera\\kernel"
|
||||||
|
edera.initrd = "\\EFI\\edera\\initrd"
|
||||||
|
edera.xen-options = ["dom0_mem=512M"]
|
||||||
|
edera.kernel-options = ["console=hvc0"]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Type | Meaning |
|
||||||
|
|------------------|-----------------|-------------------------------------------------------------|
|
||||||
|
| `xen` | string | The Xen EFI image. Required. |
|
||||||
|
| `kernel` | string | The dom0 kernel. Required. |
|
||||||
|
| `initrd` | string | The dom0 initrd. |
|
||||||
|
| `initrd-chain` | list of strings | Several initrds, concatenated in order. Can't be used with `initrd`. |
|
||||||
|
| `kernel-options` | list of strings | Command line of the dom0 kernel. |
|
||||||
|
| `xen-options` | list of strings | Command line of Xen. |
|
||||||
|
|
||||||
|
When a TPM is present, the Xen options and dom0 command line are measured into PCR 12, the kernel into
|
||||||
|
PCR 11, and the initrd into PCR 9.
|
||||||
|
|
||||||
|
## `entries`
|
||||||
|
|
||||||
|
An entry is something the user can pick from the menu. The table name identifies it.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[entries.boot-linux]
|
||||||
|
title = "Boot Linux"
|
||||||
|
actions = ["boot-linux"]
|
||||||
|
values.kernel = "\\vmlinuz"
|
||||||
|
sort-key = "10"
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Type | Meaning |
|
||||||
|
|------------|-----------------|------------------------------------------------------------------------|
|
||||||
|
| `title` | string | The text in the menu. Required, and can use values. |
|
||||||
|
| `actions` | list of strings | Actions to run, in order, when the entry is chosen. |
|
||||||
|
| `values` | table | Values that exist only for this entry. |
|
||||||
|
| `sort-key` | string | Orders the entry in the menu. Compared as versions, not as text, so `10` sorts after `9`. Defaults to the entry's name. |
|
||||||
|
|
||||||
|
The menu lists entries in reverse sort order, newest first. That is what you want for kernel versions and
|
||||||
|
is why `sort-key = "$version"` gives a sensible menu.
|
||||||
|
|
||||||
|
`--boot` and the bootloader interface find an entry by its name, by its title, or by its position in the
|
||||||
|
menu counted from 0. A `*` in the pattern matches anything.
|
||||||
|
|
||||||
|
If an entry fails Sprout reports the error and waits ten seconds. Then it exits to the firmware, or resets the
|
||||||
|
machine when `reboot-on-error` applies (see [boot counting](#boot-counting)).
|
||||||
|
|
||||||
|
## `generators`
|
||||||
|
|
||||||
|
A generator makes entries from data when Sprout starts. Each has a kind (`matrix`, `list` or `bls`), and
|
||||||
|
optionally `variants` and `exclude`, which work on the result of any kind. Set only one kind per generator.
|
||||||
|
|
||||||
|
The entries a generator makes are named `<generator>-<n>`, with `n` counting from 0, and a BLS generator
|
||||||
|
uses the name of the entry file instead. Every one of them is built from the `entry` template you give,
|
||||||
|
which takes the same keys as an [entry](#entries).
|
||||||
|
|
||||||
|
### `matrix`
|
||||||
|
|
||||||
|
Makes an entry for every combination of the lists you give.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[generators.kernels]
|
||||||
|
matrix.entry.title = "Boot $kernel with $console"
|
||||||
|
matrix.entry.actions = ["boot-kernel"]
|
||||||
|
matrix.values.kernel = ["\\vmlinuz", "\\vmlinuz-lts"]
|
||||||
|
matrix.values.console = ["ttyS0", "tty0"]
|
||||||
|
```
|
||||||
|
|
||||||
|
That is four entries. A list of two and a list of three give six.
|
||||||
|
|
||||||
|
### `list`
|
||||||
|
|
||||||
|
Makes one entry per item. Each item is a table of values. Use it when the combinations aren't a clean grid.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[generators.systems]
|
||||||
|
list.entry.title = "Boot $name"
|
||||||
|
list.entry.actions = ["boot-system"]
|
||||||
|
list.values = [
|
||||||
|
{ name = "Alpine", kernel = "\\alpine\\vmlinuz" },
|
||||||
|
{ name = "Debian", kernel = "\\debian\\vmlinuz" },
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### `bls`
|
||||||
|
|
||||||
|
Makes entries from the files of the [Bootloader Specification](#bootloader-specification-support).
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[generators.bls]
|
||||||
|
bls.path = "\\loader"
|
||||||
|
bls.entry.title = "$title"
|
||||||
|
bls.entry.actions = ["boot-bls"]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Key | Type | Default | Meaning |
|
||||||
|
|--------------|---------|-------------------|-------------------------------------------------------------------|
|
||||||
|
| `entry` | table | | The template entry. Required. |
|
||||||
|
| `path` | string | `\loader` | The directory that holds the `entries` directory. Can include a device, like `$boot\\loader`. |
|
||||||
|
| `uki-path` | string | `\EFI\Linux` on the device of `path` | Where to look for unified kernel images. An empty string turns them off. |
|
||||||
|
| `xbootldr` | boolean | `false` | Also read the extended boot loader partition of the same disk. |
|
||||||
|
| `pin-names` | boolean | `true` | Keep the entry file's name as the entry name, instead of prefixing the generator name. |
|
||||||
|
|
||||||
|
Two generators reading the same directory produce entries with the same name. Sprout warns about it, since
|
||||||
|
picking by name becomes ambiguous. `pin-names` is what makes names match the ids that `bootctl` uses.
|
||||||
|
|
||||||
|
The values each BLS entry provides are listed under [BLS values](#bls-values).
|
||||||
|
|
||||||
|
### `variants`
|
||||||
|
|
||||||
|
Variants multiply the entries of a generator. Each key is an axis, and each axis is a list of choices.
|
||||||
|
Every entry is made once for each combination of choices, taking one from each axis.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[generators.kernels]
|
||||||
|
matrix.entry.title = "Boot $kernel ($console)"
|
||||||
|
matrix.entry.actions = ["boot-kernel"]
|
||||||
|
matrix.values.kernel = ["\\vmlinuz", "\\vmlinuz-lts"]
|
||||||
|
variants.console = [
|
||||||
|
{ name = "serial", values.console-options = "console=ttyS0" },
|
||||||
|
{ name = "graphics", values.console-options = "console=tty0" },
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
This makes "Boot \vmlinuz (serial)", "Boot \vmlinuz (graphics)" and the same two for `\vmlinuz-lts`. Four
|
||||||
|
entries from a matrix of two kernels and two choices.
|
||||||
|
|
||||||
|
A choice has a `name` and optional `values`. The axis name becomes a value holding the choice's name
|
||||||
|
(`$console` is `serial` here), and the choice's own values are added next to it. Names are appended to the
|
||||||
|
entry name, so the entries above are called `kernels-0-serial`, `kernels-0-graphics` and so on. Axes apply in
|
||||||
|
alphabetical order, choices in the order written. An axis with no choices, or two choices that share a name,
|
||||||
|
is an error.
|
||||||
|
|
||||||
|
### `exclude`
|
||||||
|
|
||||||
|
Drops generated entries. It's a list of rules, and a rule is a table of value names to patterns, where `*`
|
||||||
|
matches anything. An entry is dropped if every value in at least one rule matches. It runs after variants,
|
||||||
|
and compares values before they are substituted.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[generators.bls]
|
||||||
|
# ...
|
||||||
|
exclude = [
|
||||||
|
{ version = "0-rescue-*" },
|
||||||
|
{ console = "graphics", mode = "debug" },
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
The first rule drops BLS rescue entries. The second drops only the one combination.
|
||||||
|
|
||||||
|
## `phases`
|
||||||
|
|
||||||
|
Phases run actions at fixed points in the boot. Each phase is a list, and each item names actions and can
|
||||||
|
add values for them.
|
||||||
|
|
||||||
|
| Phase | Runs |
|
||||||
|
|-----------|------------------------------------------------------------|
|
||||||
|
| `early` | Before drivers load. |
|
||||||
|
| `startup` | After drivers, autoconfiguration and extractors, before the menu is built. |
|
||||||
|
| `late` | After an entry is chosen, before its actions run. |
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[phases.early]]
|
||||||
|
actions = ["splash"]
|
||||||
|
|
||||||
|
[[phases.startup]]
|
||||||
|
actions = ["announce"]
|
||||||
|
values.message = "drivers are loaded"
|
||||||
|
```
|
||||||
|
|
||||||
|
Items run in order, and an action that fails stops the boot with an error. Note the double brackets: each
|
||||||
|
item is one element of a list.
|
||||||
|
|
||||||
|
## Autoconfiguration
|
||||||
|
|
||||||
|
With `autoconfigure = true`, or `--autoconfigure`, Sprout looks at every filesystem it can read and adds
|
||||||
|
configuration for what it finds. With the option, the result is added to your file. With the flag, your file
|
||||||
|
is not read at all, which makes it a good way to get a machine booting before you've written one.
|
||||||
|
|
||||||
|
For each filesystem:
|
||||||
|
|
||||||
|
- **BLS**: if it has `\loader\loader.conf`, a `\loader\entries` directory with `.conf` files, or `.efi` files
|
||||||
|
in `\EFI\Linux`, Sprout adds a `bls` generator and the action that boots its entries. These are named
|
||||||
|
`auto-bls-<hash>`.
|
||||||
|
- **Linux**: if there was no BLS, kernels in `\boot` and `\` are found by name (`vmlinuz` or `Image`,
|
||||||
|
optionally followed by `-` and a version), paired with an `initramfs`, `initrd` or `initrd.img` of the same
|
||||||
|
suffix. The entries are named `auto-linux-<hash>` and titled "Boot Linux" plus the path. Command line
|
||||||
|
options come from the value `linux-options`, which you can set in `[values]` and which otherwise is the
|
||||||
|
placeholder `placeholder`.
|
||||||
|
- **Windows**: if `\EFI\Microsoft\Boot\bootmgfw.efi` exists, an entry "Boot Windows" named
|
||||||
|
`auto-windows-<hash>` chainloads it.
|
||||||
|
|
||||||
|
`<hash>` is a short hash of the filesystem's device path, so two disks never collide. [Strict
|
||||||
|
mode](#strict-mode) narrows which filesystems the BLS part reads.
|
||||||
|
|
||||||
|
## Bootloader Specification support
|
||||||
|
|
||||||
|
Sprout implements the [Boot Loader Specification](https://uapi-group.org/specifications/specs/boot_loader_specification/)
|
||||||
|
to read the entries that distributions install, and sorts them as the specification says.
|
||||||
|
|
||||||
|
It reads Type #1 entries from `\loader\entries` and Type #2 unified kernel images (UKIs) from `\EFI\Linux`. A
|
||||||
|
UKI with several profiles is one entry per profile. Entries for another architecture than the machine's are
|
||||||
|
hidden. In a Type #1 entry Sprout uses the keys `title`, `version`, `machine-id`, `sort-key`, `linux`, `efi`,
|
||||||
|
`uki`, `initrd`, `options`, `devicetree`, `architecture` and `profile`.
|
||||||
|
|
||||||
|
The simplest way to get this is `autoconfigure = true`. To write it out by hand, you need a `bls` generator
|
||||||
|
and an action that boots what it makes:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[generators.bls]
|
||||||
|
bls.entry.title = "$title"
|
||||||
|
bls.entry.actions = ["boot-bls"]
|
||||||
|
bls.xbootldr = true
|
||||||
|
|
||||||
|
[actions.boot-bls]
|
||||||
|
chainload.path = "$entry-root\\$chainload"
|
||||||
|
chainload.options = ["$options"]
|
||||||
|
chainload.devicetree = "$entry-root\\$devicetree"
|
||||||
|
chainload.linux-initrd-chain = [
|
||||||
|
"$entry-root\\$initrd-0",
|
||||||
|
"$entry-root\\$initrd-1",
|
||||||
|
"$entry-root\\$initrd-2",
|
||||||
|
"$entry-root\\$initrd-3",
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
An entry can have up to 32 initrds, and Sprout warns when it has one that the chain doesn't list, because
|
||||||
|
the kernel likely can't then find its root. Autoconfiguration lists all 32. Unused slots are empty and
|
||||||
|
skipped, so listing more than you need costs nothing.
|
||||||
|
|
||||||
|
### BLS values
|
||||||
|
|
||||||
|
| Value | Holds |
|
||||||
|
|----------------------|----------------------------------------------------------------------------|
|
||||||
|
| `$title` | The title, with the version added unless it already contains it. |
|
||||||
|
| `$title-base` | The title as written in the entry. |
|
||||||
|
| `$version` | The `version` field. |
|
||||||
|
| `$machine-id` | The `machine-id` field. |
|
||||||
|
| `$chainload` | The path of the `linux`, `efi` or `uki` file. |
|
||||||
|
| `$options` | The `options` field, with the profile prepended for a UKI profile. |
|
||||||
|
| `$cmdline` | The command line embedded in a UKI. |
|
||||||
|
| `$uname` | The kernel version embedded in a UKI. |
|
||||||
|
| `$devicetree` | The `devicetree` path. |
|
||||||
|
| `$initrd-0` to `$initrd-31` | The initrds, in order. A slot with none is empty. |
|
||||||
|
| `$initrd` | The last initrd. |
|
||||||
|
| `$entry-root` | The device the entry's files are on. Empty for Sprout's own partition. |
|
||||||
|
|
||||||
|
`$entry-root` matters once `xbootldr` is on, since an entry on the XBOOTLDR partition has its files there,
|
||||||
|
not next to Sprout. Always write BLS paths as `$entry-root\\$chainload`.
|
||||||
|
|
||||||
|
### Boot counting
|
||||||
|
|
||||||
|
A file named like `fedora+3.conf` or `fedora+3.efi` has three tries. Each boot renames it, say to
|
||||||
|
`fedora+2-1.conf`, and tells the system the new path in `LoaderBootCountPath` so `systemd-bless-boot` can
|
||||||
|
remove the counter once the boot works.
|
||||||
|
|
||||||
|
Entries with no tries left sort last and are never the default, but can still be booted by hand. If an entry
|
||||||
|
fails to start after it used a try, and it had tries left, the machine resets so the next boot can use the
|
||||||
|
next try or pick another entry. This is the `reboot-on-error` setting of `loader.conf`. Without boot counting
|
||||||
|
a failure to start goes back to the firmware.
|
||||||
|
|
||||||
|
### `loader.conf`
|
||||||
|
|
||||||
|
Sprout reads `\loader\loader.conf` from the partition it was loaded from, as systemd-boot does. It is
|
||||||
|
measured into the TPM, since it changes how Sprout boots.
|
||||||
|
|
||||||
|
| Key | Value |
|
||||||
|
|-------------------|--------------------------------------------------------------------|
|
||||||
|
| `default` | A pattern for the id of the default entry, or `@saved`. |
|
||||||
|
| `preferred` | Like `default`, but entries with no boot counter tries are skipped. |
|
||||||
|
| `timeout` | Seconds, `menu-hidden`, `menu-disabled` or `menu-force`. |
|
||||||
|
| `reboot-on-error` | `auto` (the default), `yes` or `no`. |
|
||||||
|
|
||||||
|
The id of an entry is its file name without the boot counter, like `fedora.conf` or `fedora.efi`. Patterns
|
||||||
|
ignore case and can use `*`, `?` and `[a-z]`. With `@saved` the entry booted last is the default.
|
||||||
|
|
||||||
|
`reboot-on-error = yes` resets after every failed start, which can loop forever. `auto` only resets when a
|
||||||
|
try was used up and some were left. Other keys are ignored with a warning.
|
||||||
|
|
||||||
|
A hidden menu, from a timeout of zero or `menu-hidden`, still opens when a key is pressed. `menu-disabled`
|
||||||
|
does not.
|
||||||
|
|
||||||
|
### The bootloader interface
|
||||||
|
|
||||||
|
Sprout uses the same firmware variables as systemd-boot, so `bootctl`, `systemctl reboot --boot-loader-entry`
|
||||||
|
and `systemd-bless-boot` work with it. It publishes `LoaderEntries`, `LoaderEntrySelected`,
|
||||||
|
`LoaderBootCountPath`, `LoaderFeatures` and `LoaderInfo`, and reads `LoaderEntryDefault`,
|
||||||
|
`LoaderEntryPreferred`, `LoaderEntryOneShot`, `LoaderEntryLastBooted`, `LoaderConfigTimeout` and
|
||||||
|
`LoaderConfigTimeoutOneShot`.
|
||||||
|
|
||||||
|
What `bootctl` sets outranks `sprout.toml`, which outranks `loader.conf`. The default entry is the first of
|
||||||
|
these that matches an entry:
|
||||||
|
|
||||||
|
1. `LoaderEntryPreferred`, then `preferred` in `loader.conf`
|
||||||
|
2. `LoaderEntryDefault`
|
||||||
|
3. `default-entry` in `sprout.toml`
|
||||||
|
4. `default` in `loader.conf`
|
||||||
|
|
||||||
|
The menu timeout is the first of these that is set:
|
||||||
|
|
||||||
|
1. the one-shot timeout, `LoaderConfigTimeoutOneShot`
|
||||||
|
2. `--menu-timeout`
|
||||||
|
3. `LoaderConfigTimeout`
|
||||||
|
4. `menu-timeout` in `sprout.toml`
|
||||||
|
5. `timeout` in `loader.conf`
|
||||||
|
|
||||||
|
A one-shot entry (`LoaderEntryOneShot`) is booted at once and without the menu, unless strict mode is on.
|
||||||
|
|
||||||
|
## Strict mode
|
||||||
|
|
||||||
|
By default Sprout departs from systemd-boot in a few places, where it is friendlier or safer for a
|
||||||
|
bootloader that reads the same files. Each departure is logged when it applies. `--bls-strict-mode`, or
|
||||||
|
`bls-strict-mode = true` under `[options]`, turns all of them off.
|
||||||
|
|
||||||
|
| Behavior | By default | In strict mode |
|
||||||
|
|---------------------------------------------------|---------------------------------------------------------|---------------------------------------------------------|
|
||||||
|
| One-shot entry (`LoaderEntryOneShot`) | Booted at once, without the menu. | Only the default for this boot. The menu and its timeout still apply. |
|
||||||
|
| Menu timeout that nothing sets | The menu is shown for 10 seconds. | The menu is hidden. |
|
||||||
|
| Default entry with no boot counter tries | Skipped for another entry. | Used, as `default` ignores the tries. |
|
||||||
|
| Entry with more than one of `linux`, `efi`, `uki` | Boots the first of them. | Hidden. |
|
||||||
|
| Entry whose file does not exist | Shown, and it fails when booted. | Hidden. |
|
||||||
|
| UKI without a name | Named after its file. | Hidden. |
|
||||||
|
| Name and version of a UKI | Name is `PRETTY_NAME` or `ID`. Version is `IMAGE_VERSION`, `VERSION_ID`, `BUILD_ID`, then `.uname`. | What systemd-boot uses. Name is `PRETTY_NAME`, `IMAGE_ID`, `NAME` or `ID`. Version is `IMAGE_VERSION`, `VERSION`, `VERSION_ID` or `BUILD_ID`. |
|
||||||
|
| Boot counter of a plain `efi` entry | Counted. | Not counted, but its tries still make it bad. |
|
||||||
|
| Extended boot loader partition | Read when `xbootldr` is set on the generator. | Always read. |
|
||||||
|
| Autoconfiguration | Reads BLS entries from every disk, one generator each. | Reads BLS entries from Sprout's partition and the XBOOTLDR of its disk, as one generator. Windows and Linux entries are found as before. |
|
||||||
|
| Boot entry that returns | Sprout exits to the firmware. | The menu is shown again. |
|
||||||
|
| Devicetree that can't be installed | Warns and boots without it. | The entry fails. |
|
||||||
|
|
||||||
|
In strict mode the actions of a hand-written generator have to use `$entry-root` for the files of an entry,
|
||||||
|
as entries can come from the extended boot loader partition.
|
||||||
@@ -58,6 +58,7 @@ We recommend running Sprout without Secure Boot for development, and with Secure
|
|||||||
|
|
||||||
### Project Documentation
|
### Project Documentation
|
||||||
|
|
||||||
|
- [Configuration Reference]
|
||||||
- [Development Guide]
|
- [Development Guide]
|
||||||
- [Contributing Guide]
|
- [Contributing Guide]
|
||||||
- [Sprout License]
|
- [Sprout License]
|
||||||
@@ -110,49 +111,9 @@ We recommend running Sprout without Secure Boot for development, and with Secure
|
|||||||
|
|
||||||
Sprout is provided as a single EFI binary called `sprout.efi`.
|
Sprout is provided as a single EFI binary called `sprout.efi`.
|
||||||
It can be chainloaded from GRUB or other UEFI bootloaders or booted into directly.
|
It can be chainloaded from GRUB or other UEFI bootloaders or booted into directly.
|
||||||
Sprout will look for \sprout.toml in the root of the EFI partition it was loaded from.
|
Sprout reads its configuration from `\sprout.toml` in the root of the EFI partition it was loaded from.
|
||||||
See [Configuration](#configuration) for how to configure sprout.
|
|
||||||
|
|
||||||
## Configuration
|
This is a configuration that boots a Linux kernel from the EFI partition:
|
||||||
|
|
||||||
Sprout is configured using a TOML file at `\sprout.toml` on the root of the EFI partition sprout was booted from.
|
|
||||||
|
|
||||||
### Command Line Options
|
|
||||||
|
|
||||||
Sprout supports some command line options that can be combined to modify behavior without the configuration file.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Boot Sprout with a specific configuration file.
|
|
||||||
$ sprout.efi --config=\path\to\config.toml
|
|
||||||
# Boot a specific entry, bypassing the menu.
|
|
||||||
$ sprout.efi --boot="Boot Xen"
|
|
||||||
# Autoconfigure Sprout, without loading a configuration file.
|
|
||||||
$ sprout.efi --autoconfigure
|
|
||||||
# Use the basic boot menu instead of the simple one.
|
|
||||||
$ sprout.efi --menu-style=basic
|
|
||||||
# Use the graphical boot menu.
|
|
||||||
$ sprout.efi --menu-style=graphical
|
|
||||||
# Show the boot menu for 10 seconds before booting the default entry.
|
|
||||||
$ sprout.efi --menu-timeout=10
|
|
||||||
# Show the boot menu even if an entry was chosen with --boot.
|
|
||||||
$ sprout.efi --force-menu
|
|
||||||
# Keep the boot console as it is when an entry is booted.
|
|
||||||
$ sprout.efi --retain-boot-console
|
|
||||||
# Follow the BLS specification and systemd-boot exactly.
|
|
||||||
$ sprout.efi --bls-strict-mode
|
|
||||||
```
|
|
||||||
|
|
||||||
### Graphical Menu
|
|
||||||
|
|
||||||
The graphical menu selects entries with the keyboard. The mouse is off by default. To use it, enable it in
|
|
||||||
`sprout.toml`. The cursor is only shown when the mouse is enabled and the firmware has a pointing device.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[menu-styles.graphical]
|
|
||||||
enable-mouse = true
|
|
||||||
```
|
|
||||||
|
|
||||||
### Boot Linux from ESP
|
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# sprout configuration: version 1
|
# sprout configuration: version 1
|
||||||
@@ -174,170 +135,24 @@ chainload.options = ["root=/dev/sda1"]
|
|||||||
chainload.linux-initrd = "\\initrd"
|
chainload.linux-initrd = "\\initrd"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Bootloader Specification (BLS) Support
|
On a system that follows the Boot Loader Specification, you may not need to write one. With an ext4 driver
|
||||||
|
loaded, autoconfiguration finds the entries on its own:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# sprout configuration: version 1
|
|
||||||
version = 1
|
version = 1
|
||||||
|
|
||||||
# load an EFI driver for ext4.
|
|
||||||
[drivers.ext4]
|
[drivers.ext4]
|
||||||
path = "\\sprout\\drivers\\ext4.efi"
|
path = "\\sprout\\drivers\\ext4.efi"
|
||||||
|
|
||||||
# global options.
|
|
||||||
[options]
|
[options]
|
||||||
# enable autoconfiguration by detecting bls enabled
|
|
||||||
# filesystems and generating boot entries for them.
|
|
||||||
autoconfigure = true
|
autoconfigure = true
|
||||||
```
|
```
|
||||||
|
|
||||||
Sprout reads Type #1 entries from `\loader\entries` and Type #2 unified kernel images (UKIs) from
|
The full list of settings, the command line options, generators, and how Sprout treats BLS entries,
|
||||||
`\EFI\Linux`, and sorts them as the specification says. A unified kernel image with several profiles
|
`loader.conf` and strict mode are in [CONFIG.md](./CONFIG.md).
|
||||||
is one entry for each profile. Entries that are not for the architecture of the machine are hidden.
|
|
||||||
Type #1 entries can use `linux`, `efi`, `uki`, `initrd`, `options`, `devicetree`, `architecture`,
|
|
||||||
`profile`, `sort-key`, `version`, `machine-id`, and `title`.
|
|
||||||
|
|
||||||
To set up the generator by hand instead of using autoconfiguration, add a generator and an action
|
|
||||||
that boots the entries. The entry values `$chainload`, `$options`, `$initrd-0` to `$initrd-7`,
|
|
||||||
`$devicetree`, `$cmdline`, `$title`, `$version`, and `$entry-root` are available.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[generators.bls]
|
|
||||||
# the directory that has the entries directory. this is the default.
|
|
||||||
bls.path = "\\loader"
|
|
||||||
# the directory of unified kernel images. by default, this is \EFI\Linux on
|
|
||||||
# the device of the path. an empty path turns unified kernel images off.
|
|
||||||
bls.uki-path = "\\EFI\\Linux"
|
|
||||||
# also read the extended boot loader partition (XBOOTLDR) of the same disk,
|
|
||||||
# which is sorted with the other entries. strict mode always does. its files are on that partition, so
|
|
||||||
# the action has to use $entry-root, which is empty for Sprout's own partition.
|
|
||||||
bls.xbootldr = false
|
|
||||||
# keep the name of the entry file as the name of the entry, so it matches
|
|
||||||
# the ids that bootctl uses.
|
|
||||||
bls.pin-names = true
|
|
||||||
bls.entry.title = "$title"
|
|
||||||
bls.entry.actions = ["boot-bls"]
|
|
||||||
|
|
||||||
[actions.boot-bls]
|
|
||||||
chainload.path = "$entry-root\\$chainload"
|
|
||||||
chainload.options = ["$options"]
|
|
||||||
chainload.devicetree = "$entry-root\\$devicetree"
|
|
||||||
# an entry can have up to 32 initrds, as $initrd-0 to $initrd-31. unused ones are skipped.
|
|
||||||
# only the first eight are listed here. add the others to boot an entry with more,
|
|
||||||
# as Sprout warns when an entry has an initrd that the chain does not list.
|
|
||||||
chainload.linux-initrd-chain = [
|
|
||||||
"$entry-root\\$initrd-0",
|
|
||||||
"$entry-root\\$initrd-1",
|
|
||||||
"$entry-root\\$initrd-2",
|
|
||||||
"$entry-root\\$initrd-3",
|
|
||||||
"$entry-root\\$initrd-4",
|
|
||||||
"$entry-root\\$initrd-5",
|
|
||||||
"$entry-root\\$initrd-6",
|
|
||||||
"$entry-root\\$initrd-7",
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
An entry that names a `devicetree` boots with that devicetree installed for the image, which is put
|
|
||||||
back when the image returns. It is not used when Secure Boot is enabled, as it can't be verified.
|
|
||||||
If it can't be installed, Sprout warns and boots without it, unless strict mode is on.
|
|
||||||
|
|
||||||
#### Boot counting
|
|
||||||
|
|
||||||
An entry file named like `fedora+3.conf` or `fedora+3.efi` has three tries. Each time Sprout boots it, the
|
|
||||||
file is renamed, such as to `fedora+2-1.conf`, and the new path is given to the system in
|
|
||||||
`LoaderBootCountPath` so `systemd-bless-boot` can remove the counter once the boot works.
|
|
||||||
Entries that have no tries left are sorted last and are not picked as the default entry, but they can still be
|
|
||||||
booted by hand. By default, if an entry fails to start after a try was used up and it had tries left, the machine
|
|
||||||
resets, so the next boot can use the next try or another entry. This is the `reboot-on-error` setting
|
|
||||||
in `loader.conf`. Without boot counting, a failure to start returns to the firmware.
|
|
||||||
|
|
||||||
#### loader.conf
|
|
||||||
|
|
||||||
Sprout reads `\loader\loader.conf` from the partition it was loaded from, as systemd-boot does.
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|-------------------|--------------------------------------------------------------------|
|
|
||||||
| `default` | A pattern for the id of the default entry, or `@saved`. |
|
|
||||||
| `preferred` | Like `default`, but entries with no boot counter tries are skipped. |
|
|
||||||
| `timeout` | Seconds, `menu-hidden`, `menu-disabled`, or `menu-force`. |
|
|
||||||
| `reboot-on-error` | `auto` (the default), `yes`, or `no`. |
|
|
||||||
|
|
||||||
The id of an entry is the name of its file without the boot counter, such as `fedora.conf` or `fedora.efi`.
|
|
||||||
Patterns ignore case and can use `*`, `?`, and `[a-z]`. With `@saved`, the entry that was booted last is the
|
|
||||||
default. With `reboot-on-error`, `yes` always resets after an entry fails to start, which can loop forever,
|
|
||||||
and `auto` only does when a boot counter try was used up and there were tries left.
|
|
||||||
Other keys are ignored with a warning.
|
|
||||||
|
|
||||||
A hidden menu, from a timeout of zero or `menu-hidden`, still opens when a key is pressed. `menu-disabled` does not.
|
|
||||||
|
|
||||||
#### Bootloader interface
|
|
||||||
|
|
||||||
Sprout uses the same variables as systemd-boot, so `bootctl`, `systemctl reboot --boot-loader-entry`, and
|
|
||||||
`systemd-bless-boot` can work with it. It publishes `LoaderEntries`, `LoaderEntrySelected`,
|
|
||||||
`LoaderBootCountPath`, `LoaderFeatures`, and `LoaderInfo`, and reads `LoaderEntryDefault`,
|
|
||||||
`LoaderEntryPreferred`, `LoaderEntryOneShot`, `LoaderEntryLastBooted`, `LoaderConfigTimeout`,
|
|
||||||
and `LoaderConfigTimeoutOneShot`.
|
|
||||||
|
|
||||||
The values that tools like `bootctl` set in the bootloader interface outrank `sprout.toml`, which outranks
|
|
||||||
`loader.conf`. In strict mode, `LoaderEntryOneShot` is tried before everything else for the default entry.
|
|
||||||
|
|
||||||
The default entry comes from the first of these that matches an entry:
|
|
||||||
|
|
||||||
1. `LoaderEntryPreferred`, then `preferred` in `loader.conf`
|
|
||||||
2. `LoaderEntryDefault`
|
|
||||||
3. `default-entry` in `sprout.toml`
|
|
||||||
4. `default` in `loader.conf`
|
|
||||||
|
|
||||||
The menu timeout comes from the first of the one-shot timeout, `--menu-timeout`, `LoaderConfigTimeout`,
|
|
||||||
`menu-timeout` in `sprout.toml`, and `loader.conf`.
|
|
||||||
|
|
||||||
#### Strict mode
|
|
||||||
|
|
||||||
By default, Sprout differs from systemd-boot in a few places that are friendlier or safer for a bootloader that
|
|
||||||
reads the same files. Each of them is logged when it applies. `--bls-strict-mode`, or `bls-strict-mode = true`
|
|
||||||
in the options of `sprout.toml`, removes all of them.
|
|
||||||
|
|
||||||
| Behavior | By default | In strict mode |
|
|
||||||
|------------------------------------------|-----------------------------------------------------------|-----------------------------------------------------------|
|
|
||||||
| One-shot entry (`LoaderEntryOneShot`) | Booted at once, without the menu. | Only the default for this boot. The menu and its timeout still apply. |
|
|
||||||
| Menu timeout that nothing sets | The menu is shown for 10 seconds. | The menu is hidden. |
|
|
||||||
| Default entry with no boot counter tries | Skipped for another entry. | Used, as `default` ignores the tries. |
|
|
||||||
| Entry with more than one of `linux`, `efi`, `uki` | Boots the first of them. | Hidden. |
|
|
||||||
| Entry whose file does not exist | Shown, and it fails when booted. | Hidden. |
|
|
||||||
| Unified kernel image without a name | Named after its file. | Hidden. |
|
|
||||||
| Name and version of a unified kernel image | The name is `PRETTY_NAME` or `ID`, and the version is `IMAGE_VERSION`, `VERSION_ID`, `BUILD_ID`, then `.uname`. | The fields systemd-boot uses: the name is `PRETTY_NAME`, `IMAGE_ID`, `NAME` or `ID`, and the version is `IMAGE_VERSION`, `VERSION`, `VERSION_ID` or `BUILD_ID`. |
|
|
||||||
| Boot counter of a plain `efi` entry | Counted. | Not counted, but its tries still make it bad. |
|
|
||||||
| The extended boot loader partition | Read when `xbootldr` is set on the generator. | Always read. |
|
|
||||||
| Autoconfiguration | Reads BLS entries from every disk, one generator each. | Reads BLS entries from Sprout's partition and the XBOOTLDR of its disk, as one generator. Windows and Linux entries are found as before. |
|
|
||||||
| Boot entry that returns | Sprout exits to the firmware. | The menu is shown again. |
|
|
||||||
| Devicetree that can't be installed | Warns and boots without it. | The entry fails. |
|
|
||||||
|
|
||||||
In strict mode, the actions of a hand-written generator have to use `$entry-root` for the files of
|
|
||||||
an entry, as entries can come from the extended boot loader partition.
|
|
||||||
|
|
||||||
### Generators
|
|
||||||
|
|
||||||
Generators make entries when Sprout starts. The `matrix` generator makes an entry for every combination of
|
|
||||||
its values, the `list` generator makes an entry for each item of a list, and the `bls` generator makes
|
|
||||||
entries from BLS files. Variants multiply the entries of any generator, and `exclude` removes some of them.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
# makes an entry for each kernel and each console, such as "Boot \vmlinuz (serial)".
|
|
||||||
[generators.kernels]
|
|
||||||
matrix.entry.title = "Boot $kernel ($console)"
|
|
||||||
matrix.entry.actions = ["boot-kernel"]
|
|
||||||
matrix.values.kernel = ["\\vmlinuz", "\\vmlinuz-lts"]
|
|
||||||
variants.console = [
|
|
||||||
{ name = "serial", values.console-options = "console=ttyS0" },
|
|
||||||
{ name = "graphics", values.console-options = "console=tty0" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[actions.boot-kernel]
|
|
||||||
chainload.path = "$kernel"
|
|
||||||
chainload.options = ["$console-options"]
|
|
||||||
```
|
|
||||||
|
|
||||||
[Edera]: https://edera.dev
|
[Edera]: https://edera.dev
|
||||||
|
[Configuration Reference]: ./CONFIG.md
|
||||||
[Development Guide]: ./DEVELOPMENT.md
|
[Development Guide]: ./DEVELOPMENT.md
|
||||||
[Contributing Guide]: ./CONTRIBUTING.md
|
[Contributing Guide]: ./CONTRIBUTING.md
|
||||||
[Sprout License]: ./LICENSE
|
[Sprout License]: ./LICENSE
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ pub struct OptionsConfiguration {
|
|||||||
/// Makes Sprout follow the Boot Loader Specification and systemd-boot exactly where it
|
/// Makes Sprout follow the Boot Loader Specification and systemd-boot exactly where it
|
||||||
/// otherwise differs for convenience or safety. For example, the extended boot loader
|
/// otherwise differs for convenience or safety. For example, the extended boot loader
|
||||||
/// partition is always read, a one-shot entry only sets the default entry, and entries with
|
/// partition is always read, a one-shot entry only sets the default entry, and entries with
|
||||||
/// missing files are hidden. See the README for everything it changes.
|
/// missing files are hidden. See CONFIG.md for everything it changes.
|
||||||
#[serde(rename = "bls-strict-mode", default)]
|
#[serde(rename = "bls-strict-mode", default)]
|
||||||
pub bls_strict_mode: bool,
|
pub bls_strict_mode: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user