mirror of
https://github.com/systemd/systemd.git
synced 2025-01-06 17:18:12 +03:00
efi/boot: add support for a fallback entry
Add support for a fallback boot entry. Fallback boot entries can be used to ensure that a system starts even if the default boot entry fails or other unexpected events happen that can prevent to use the default boot entry (boot firmware failure, failed A/B OTA update etc). The EFI variable `LoaderEntryFallback` contains the fallback boot loader entry to use. config_is_fallback_required() expected to be extented to support possible conditions when we should fall back to "recovery" boot entry. Signed-off-by: Igor Opaniuk <igor.opaniuk@foundries.io>
This commit is contained in:
parent
a95aacc851
commit
c2327afbfe
@ -102,6 +102,7 @@ Some EFI variables control the loader or exported the loaders state to the start
|
||||
| EFI Variables |
|
||||
|---------------|------------------------|-------------------------------|
|
||||
| LoaderEntryDefault | entry identifier to select as default at bootup | non-volatile |
|
||||
| LoaderEntryFallback | fallback entry identifier | non-volatile |
|
||||
| LoaderConfigTimeout | timeout in seconds to show the menu | non-volatile |
|
||||
| LoaderEntryOneShot | entry identifier to select at the next and only the next bootup | non-volatile |
|
||||
| LoaderDeviceIdentifier | list of identifiers of the volume the loader was started from | volatile |
|
||||
|
@ -58,6 +58,11 @@ variables. All EFI variables use the vendor UUID
|
||||
* The EFI variable `LoaderEntryDefault` contains the default boot loader entry
|
||||
to use. It contains a NUL-terminated boot loader entry identifier.
|
||||
|
||||
* The EFI variable `LoaderEntryFallback` contains the fallback boot loader entry
|
||||
to use. Fallback boot entries can be used to ensure that a system starts even
|
||||
if the default boot entry fails or other unexpected event happened (boot firmware
|
||||
failure etc.). It contains a NUL-terminated boot loader entry identifier.
|
||||
|
||||
* Similarly, the EFI variable `LoaderEntryOneShot` contains the default boot
|
||||
loader entry to use for a single following boot. It is set by the OS in order
|
||||
to request booting into a specific menu entry on the following boot. When set
|
||||
|
@ -146,8 +146,9 @@
|
||||
<option>@oneshot</option> or <option>@current</option>, which correspond to the current default boot loader
|
||||
entry for all future boots, the current default boot loader entry for the next boot, and the currently booted
|
||||
boot loader entry. These special IDs are resolved to the current values of the EFI variables
|
||||
<varname>LoaderEntryDefault</varname>, <varname>LoaderEntryOneShot</varname> and <varname>LoaderEntrySelected</varname>,
|
||||
see <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink> for details.
|
||||
<varname>LoaderEntryDefault</varname>, <varname>LoaderEntryFallback</varname>, <varname>LoaderEntryOneShot</varname>
|
||||
and <varname>LoaderEntrySelected</varname>, see <ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">
|
||||
Boot Loader Specification</ulink> for details.
|
||||
These special IDs are primarily useful as a quick way to persistently make the currently booted boot loader
|
||||
entry the default choice, or to upgrade the default boot loader entry for the next boot to the default boot
|
||||
loader entry for all future boots, but may be used for other operations too.</para>
|
||||
|
@ -451,6 +451,7 @@
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>LoaderEntryDefault</varname></term>
|
||||
<term><varname>LoaderEntryFallback</varname></term>
|
||||
<term><varname>LoaderEntryOneShot</varname></term>
|
||||
|
||||
<listitem><para>The identifier of the default boot loader entry. Set primarily by the OS and read by the boot
|
||||
|
@ -1019,6 +1019,7 @@ static int remove_loader_variables(void) {
|
||||
EFI_LOADER_VARIABLE(LoaderConfigTimeout),
|
||||
EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot),
|
||||
EFI_LOADER_VARIABLE(LoaderEntryDefault),
|
||||
EFI_LOADER_VARIABLE(LoaderEntryFallback),
|
||||
EFI_LOADER_VARIABLE(LoaderEntryLastBooted),
|
||||
EFI_LOADER_VARIABLE(LoaderEntryOneShot),
|
||||
EFI_LOADER_VARIABLE(LoaderSystemToken)) {
|
||||
|
@ -88,6 +88,11 @@ static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
|
||||
|
||||
} else if (streq(arg1, "@fallback")) {
|
||||
r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryFallback), NULL, (void *) ret_target, ret_target_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryFallback': %m");
|
||||
|
||||
} else if (arg1[0] == '@' && !streq(arg1, "@saved"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unsupported special entry identifier: %s", arg1);
|
||||
else {
|
||||
@ -139,6 +144,9 @@ int verb_set_efivar(int argc, char *argv[], void *userdata) {
|
||||
if (streq(argv[0], "set-default")) {
|
||||
variable = EFI_LOADER_VARIABLE(LoaderEntryDefault);
|
||||
arg_parser = parse_loader_entry_target_arg;
|
||||
} else if (streq(argv[0], "set-fallback")) {
|
||||
variable = EFI_LOADER_VARIABLE(LoaderEntryFallback);
|
||||
arg_parser = parse_loader_entry_target_arg;
|
||||
} else if (streq(argv[0], "set-oneshot")) {
|
||||
variable = EFI_LOADER_VARIABLE(LoaderEntryOneShot);
|
||||
arg_parser = parse_loader_entry_target_arg;
|
||||
|
@ -88,6 +88,7 @@ typedef struct {
|
||||
uint64_t timeout_sec_config;
|
||||
uint64_t timeout_sec_efivar;
|
||||
char16_t *entry_default_config;
|
||||
char16_t *entry_fallback;
|
||||
char16_t *entry_default_efivar;
|
||||
char16_t *entry_oneshot;
|
||||
char16_t *entry_saved;
|
||||
@ -525,6 +526,8 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
|
||||
|
||||
if (config->entry_default_config)
|
||||
printf(" default (config): %ls\n", config->entry_default_config);
|
||||
if (config->entry_fallback)
|
||||
printf(" default (fallback): %ls\n", config->entry_fallback);
|
||||
if (config->entry_default_efivar)
|
||||
printf(" default (EFI var): %ls\n", config->entry_default_efivar);
|
||||
if (config->entry_oneshot)
|
||||
@ -1634,8 +1637,10 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
|
||||
(void) efivar_unset(MAKE_GUID_PTR(LOADER), u"LoaderEntryOneShot", EFI_VARIABLE_NON_VOLATILE);
|
||||
|
||||
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryDefault", &config->entry_default_efivar);
|
||||
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryFallback", &config->entry_fallback);
|
||||
|
||||
strtolower16(config->entry_default_config);
|
||||
strtolower16(config->entry_fallback);
|
||||
strtolower16(config->entry_default_efivar);
|
||||
strtolower16(config->entry_oneshot);
|
||||
strtolower16(config->entry_saved);
|
||||
@ -1777,11 +1782,25 @@ static size_t config_find_entry(Config *config, const char16_t *pattern) {
|
||||
return IDX_INVALID;
|
||||
}
|
||||
|
||||
static bool config_is_fallback_required(Config *config) {
|
||||
assert(config);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void config_select_default_entry(Config *config) {
|
||||
size_t i;
|
||||
|
||||
assert(config);
|
||||
|
||||
if (config_is_fallback_required(config)) {
|
||||
i = config_find_entry(config, config->entry_fallback);
|
||||
if (i != IDX_INVALID) {
|
||||
config->idx_default = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
i = config_find_entry(config, config->entry_oneshot);
|
||||
if (i != IDX_INVALID) {
|
||||
config->idx_default = i;
|
||||
@ -2643,6 +2662,7 @@ static void config_free(Config *config) {
|
||||
boot_entry_free(config->entries[i]);
|
||||
free(config->entries);
|
||||
free(config->entry_default_config);
|
||||
free(config->entry_fallback);
|
||||
free(config->entry_default_efivar);
|
||||
free(config->entry_oneshot);
|
||||
free(config->entry_saved);
|
||||
|
@ -1394,6 +1394,12 @@ static int boot_load_efi_entry_pointers(BootConfig *config, bool skip_efivars) {
|
||||
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
|
||||
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\", ignoring: %m");
|
||||
|
||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntryFallback), &config->entry_fallback);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
|
||||
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryFallback\", ignoring: %m");
|
||||
|
||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderEntrySelected), &config->entry_selected);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
|
@ -71,6 +71,7 @@ typedef struct BootConfig {
|
||||
|
||||
char *entry_oneshot;
|
||||
char *entry_default;
|
||||
char *entry_fallback;
|
||||
char *entry_selected;
|
||||
|
||||
BootEntry *entries;
|
||||
|
Loading…
Reference in New Issue
Block a user