* The EFI variable `LoaderEntryDefault` contains the default boot loader entry
to use. It contains a NUL-terminated boot loader entry identifier.
+* The EFI variable `LoaderEntrySysFail` specifies the boot loader entry to be
+ used in case of a system failure. System failure (SysFail) boot entries can
+ optionally modify the automatic selection order in the event of a failure,
+ such as a boot firmware update failure with the failure status recorded in
+ the EFI system table. If a system failure occurs and `LoaderEntrySysFail` is set,
+ systemd-boot will use this boot entry and store the actual SysFail reason in
+ the `LoaderSysFailReason` EFI variable.
+
+* The EFI variable `LoaderSysFailReason` contains the system failure reason.
+ This variable is used in cooperation with `LoaderEntrySysFail` boot entry.
+ If system failure doesn't occur `LoaderSysFailReason` is not set at all.
+
* 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
#include "shim.h"
#include "smbios.h"
#include "strv-fundamental.h"
+#include "sysfail.h"
#include "ticks.h"
#include "tpm2-pcr.h"
#include "uki.h"
char16_t *entry_default_efivar;
char16_t *entry_oneshot;
char16_t *entry_saved;
+ char16_t *entry_sysfail;
bool editor;
bool auto_entries;
bool auto_firmware;
bool use_saved_entry;
bool use_saved_entry_efivar;
bool beep;
+ bool sysfail_occured;
int64_t console_mode;
int64_t console_mode_efivar;
} Config;
printf(" default (EFI var): %ls\n", config->entry_default_efivar);
if (config->entry_oneshot)
printf(" default (one-shot): %ls\n", config->entry_oneshot);
+ if (config->entry_sysfail)
+ printf(" sysfail: %ls\n", config->entry_sysfail);
if (config->entry_saved)
printf(" saved entry: %ls\n", config->entry_saved);
printf(" editor: %ls\n", yes_no(config->editor));
(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"LoaderEntrySysFail", &config->entry_sysfail);
strtolower16(config->entry_default_config);
strtolower16(config->entry_default_efivar);
strtolower16(config->entry_oneshot);
strtolower16(config->entry_saved);
+ strtolower16(config->entry_sysfail);
config->use_saved_entry = streq16(config->entry_default_config, u"@saved");
config->use_saved_entry_efivar = streq16(config->entry_default_efivar, u"@saved");
return IDX_INVALID;
}
+static bool sysfail_process(Config *config) {
+ SysFailType sysfail_type;
+
+ assert(config);
+
+ sysfail_type = sysfail_check();
+ if (sysfail_type == SYSFAIL_NO_FAILURE)
+ return false;
+
+ /* Store reason string in LoaderSysFailReason EFI variable */
+ const char16_t *reason_str = sysfail_get_error_str(sysfail_type);
+ if (reason_str)
+ (void) efivar_set_str16(MAKE_GUID_PTR(LOADER), u"LoaderSysFailReason", reason_str, 0);
+
+ config->sysfail_occured = true;
+
+ return true;
+}
+
static void config_select_default_entry(Config *config) {
size_t i;
assert(config);
+ if (config->sysfail_occured) {
+ i = config_find_entry(config, config->entry_sysfail);
+ 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;
free(config->entry_default_efivar);
free(config->entry_oneshot);
free(config->entry_saved);
+ free(config->entry_sysfail);
}
static void config_write_entries_to_variable(Config *config) {
_cleanup_free_ char16_t *loaded_image_path = NULL;
(void) device_path_to_str(loaded_image->FilePath, &loaded_image_path);
config_load_all_entries(&config, loaded_image, loaded_image_path, root_dir);
+ (void) sysfail_process(&config);
if (config.n_entries == 0)
return log_error_status(
free(config->entry_oneshot);
free(config->entry_default);
free(config->entry_selected);
+ free(config->entry_sysfail);
FOREACH_ARRAY(i, config->entries, config->n_entries)
boot_entry_free(i);
if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
log_warning_errno(r, "Failed to read EFI variable \"LoaderEntrySelected\", ignoring: %m");
+ r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderEntrySysFail"), &config->entry_sysfail);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA))
+ log_warning_errno(r, "Failed to read EFI variable \"LoaderEntrySysFail\", ignoring: %m");
+
return 1;
}