systemd-boot might be installed in /EFI/BOOT under more names than
just /EFI/BOOT/BOOTX64.efi. The prime example is shim which loads
its second stage binary from /EFI/BOOT/grubx64.efi. To accomodate
use cases where systemd-boot is installed as /EFI/BOOT/grubx64.efi,
let's always check the entire /EFI/BOOT directory for binaries that
identify as systemd-boot and list/update/remove those as well.
Let's keep this somewhat generic though and not install ourselves as
grubx64.efi since that would mean having to check for shim which is
a can of worms we probably don't want to open.
Output is otherwise so weird, since this is the last log line seen for a
while typically, and if it doesn#t put the cursor back in the first
column it looks like something is incomplete and hanging. Hence do what
we always do: finish log messages with a newline.
Firmware may not have loaded a devicetree, for example if the device
shipped with windows and exclusively supports ACPI.
We should always load the specified devicetree regardless of firmware
state to enable booting on platforms where Linux only supports DT.
Note: in _cleanup, the orig. config is NULL in this case, and passing
NULL to InstallConfigurationTable is permitted by the EFI spec.
See: https://uefi.org/specs/UEFI/2.10/07_Services_Boot_Services.htmlFixes#24059
Co-authored-by: Daniel Thompson <daniel.thompson@linaro.org>
When testing the secureboot enroll feature, it can be hard to distinguish without
using the QMP API of QEMU whether we are in a hang situation of the UEFI firmware.
Making it clear that we reached the `ResetSystem` can be helpful towards that need.
Same idea as with bootctl, we might be doing image builds from a
system that doesn't boot with UEFI but we still might want to measure
stuff for the image we're building so let's not gate this behind
ENABLE_BOOTLOADER.
bootctl is rather useful to have, even if on a system without UEFI,
as it has a number of verbs that are unrelated to UEFI (e.g kernel-identify),
and more importantly, it supports --root to operate on directory trees
(which could be intended to be deployed on UEFI) so let's make sure we
always build it.
If `foo+3-0.efi` is booted when there are some files in `foo.efi.extra.d`,
those files are ignored. But after the boot is blessed and the system rebooted,
those file are taken into account, and the boot is different from first
boot. This behavior is a bit puzzling.
Instead we now ignore the counter and always look for the extra files in
`foo.efi.extra.d` and always boot the same way.
Ultimately we want to be able to recognize these in userspace, hence
make them available in both UEFI mode and userspace.
While we are at it, let's rename the fields a bit, reflecting more what
they measure, not what the metadata is that we store about them.
We usually check return value of syscalls or glibc functions by it is
negative or not, something like that `if (stat(path, &st) < 0)`.
Let's also use the same style for lseek() and friends even the type of
their return value is off_t.
Note, fseeko() returns int, instead of off_t.
Currently we have a 100ms delay which allows for people to enter/show
the boot menu even when timeout is set to zero.
In a handful of cases, that may not be needed - both in terms of access
policy, as well as latency.
For example: the option to provide the boot menu may be hidden behind an
"expert only" UX in the OS, to avoid end users from accidentally
entering it.
In addition, the current 100ms input polling may cause unexpected
additional delays in the boot. Some example numbers from my SteamDeck:
- boot counting/rename/flush doubles 300us -> 600us
- seed/hash setup doubles 900us -> 1800us
- kernel/image load gets ~40% slower 107ms -> 167ms
It's not entirely clear why the UEFI calls gets slower, nevertheless the
information in itself proves useful.
This commit introduces a new option "menu-disabled", which omits the
100ms delay. The option is documented throughout the manual pages as
well as the Boot Loader Specification.
v2:
- use STR_IN_SET
v3:
- drop erroneous whitespace
v4:
- add a new LoaderFeature bit,
- don't change ABI keep TIMEOUT_* tokens the same
- move new token in the 64bit range, update API and storage for it
- change inc/dec behaviour to TIMEOUT_MIN : TIMEOUT_MENU_FORCE
- user cannot opt-in from sd-boot itself, add assert_not_reached()
v5:
- s/Menu disablement control/Menu can be disabled/
- rewrap comments to 109
- use SYNTHETIC_ERRNO(EOPNOTSUPP)
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
UKIs may be loaded in a way, that there can not be a device handle to
the filesystem, that contains the image, for example when using a
bootloader to load the image from a partition with a file system that is
not supported by the firmware.
With the current systemd stub, this causes a failed assertion, because
stub gets passed a NULL DeviceHandle and FilePath. Inserting two
explicit checks enables proper boot even in this case.
Fixes: #29331
Some of the entries are really configured, but we also have a bunch
of automatic entries. Calling them "config entries" is misleading, let's
use the more natural "boot entry".
While at it, rename:
config_load_entries() → config_load_type1_entries()
config_entry_add_unified() → config_load_type2_entries()
config_title_generate() → generate_boot_entry_titles()
config_entry_add_<type>() → config_add_entry_<type>()
No functional change.
When the user pressed + or -, we would set the efivar override, starting
from the default of 0. Instead, set an override that starts at the current
value. This means that when user has e.g. a configured override of 5 s, and
they press +, they get an override of 6 s. I think this is leads to a much
smoother experience for a user, who does not necessarilly need to know that
we have three levels of overrides, they just want to easily configure the
timeout with keys. If they press +, the timeout should increase, and not
jump to some low value.
Also, once an override has been set via the boot menu, i.e. the efivar is set,
do not allow unsetting the efivar from the boot menu. This way we also avoid
an unexpected "jump" to whatever the other sources of configuration specify.
The user can configure any value with the keys that they want, so we don't
need to allow unsetting.
The menu_run() function allows the user to set/unset default entry, or to
increase/decrease menu timeout. After a keypress, status like
"Menu timeout set to 5 s"
is printed, but there actually isn't any immediate effect. The value is only
written right right before booting a menu entry to avoid unnecessary wear&tear
on the nvram storage. This delayed write is supposed to be invisible to the
user.
Nevertheless, operations like reboot into firmware, reboot, or shutdown were
done immediately. We need to exit the loop first, save the state, and only do
the op afterwards.
Fixup for f6531b11d2 and
e6cab77eca.
Also reverts 498d0cc426.
Currently only an auto-reboot-to-firmware entry is available. For other
features - like reboot and power off - one needs to press the uppercase
B and O respectively.
Embedded devices may be missing a full fledged keyboard, so allow for
sd-boot to generate those entries.
v2:
- add to the config parser/man/bootctl/sd-boot info screen
- keep them off by default
- add the (O)ff and re(B)oot help text if boot entries are not shown
- drop irrelevant get_os_indications_supported() comment
- s/ShutDown/Shutdown/
v3:
- cast shutdown_system() reboot_system() to void
v4:
- shutdown -> poweroff
- add trailing ",ignoring" in parser message
- drop explicit default state assignment to "false"
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
As mentioned by Lennart:
... we typically suffix such messages with ", ignoring", to indicate
that we don't consider this fatal for anything.
Update config_defaults_load_from_file() to follow that pattern.
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
When the assignment is missing, the default 0/NULL/false value is used.
So drop the explicit piece in config_load_defaults()
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
As mentioned by Lennart, in a commit where I was adding similar piece of
code:
maybe cast this call to void, to tell static analyzers that we are
ignoring the return value on purpose, not by accident
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Grepping around showed a few extra entries that are not listed in the
remove_loader_variables() function. Namely:
- BootNext
- OsIndications
- LoaderConfigConsoleMode
- LoaderEntryLastBooted
Of which the latter two are systemd specific, even though they are
undocumented. Ensure they're removed - follow-up commits will add
documentation references.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Currently some of the code base check for the variable presence before
removing it, and some do not.
More so, in all cases (being updated) we're dealing with non-volatile
variables where changing those attribute to NVRAM wear out.
From what information I could find, there is no definitive answer if the
UEFI implementation will write to the NVRAM even when the variable is
missing.
So add a simple helper that checks for the variable presence before
removing it. While also having a bit cleaner API than the current
efivar_set(..., NULL, ...);
efivar_unset() follows the design from efivar_set*() where it returns an
EFI_STATUS even though its (presently) unused.
v2:
- add inline comment, use early return
v3:
- typos? typos!
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>