mirror of
https://github.com/systemd/systemd.git
synced 2024-10-26 08:55:40 +03:00
Merge e2e42056fd
into f7078de515
This commit is contained in:
commit
d2e628b91e
@ -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;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "proto/device-path.h"
|
||||
#include "proto/simple-text-io.h"
|
||||
#include "random-seed.h"
|
||||
#include "recovery.h"
|
||||
#include "sbat.h"
|
||||
#include "secure-boot.h"
|
||||
#include "shim.h"
|
||||
@ -88,6 +89,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;
|
||||
@ -97,6 +99,7 @@ typedef struct {
|
||||
bool auto_poweroff;
|
||||
bool auto_reboot;
|
||||
bool reboot_for_bitlocker;
|
||||
bool fallback_firmware_failure;
|
||||
secure_boot_enroll secure_boot_enroll;
|
||||
bool force_menu;
|
||||
bool use_saved_entry;
|
||||
@ -525,6 +528,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)
|
||||
@ -538,6 +543,7 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
|
||||
printf(" auto-reboot: %ls\n", yes_no(config->auto_reboot));
|
||||
printf(" beep: %ls\n", yes_no(config->beep));
|
||||
printf(" reboot-for-bitlocker: %ls\n", yes_no(config->reboot_for_bitlocker));
|
||||
printf(" fallback-firmware-failure: %ls\n", yes_no(config->fallback_firmware_failure));
|
||||
|
||||
switch (config->secure_boot_enroll) {
|
||||
case ENROLL_OFF:
|
||||
@ -1275,6 +1281,10 @@ static void config_defaults_load_from_file(Config *config, char *content) {
|
||||
if (!parse_boolean(value, &config->reboot_for_bitlocker))
|
||||
log_error("Error parsing 'reboot-for-bitlocker' config option, ignoring: %s",
|
||||
value);
|
||||
} else if (streq8(key, "fallback-firmware-failure")) {
|
||||
if (!parse_boolean(value, &config->fallback_firmware_failure))
|
||||
log_error("Error parsing 'fallback-firmware-failure' config option, ignoring: %s",
|
||||
value);
|
||||
|
||||
} else if (streq8(key, "secure-boot-enroll")) {
|
||||
if (streq8(value, "manual"))
|
||||
@ -1634,8 +1644,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 +1789,29 @@ 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);
|
||||
|
||||
if (config->fallback_firmware_failure) {
|
||||
return recovery_check_firmware_failure();
|
||||
}
|
||||
|
||||
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 +2673,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);
|
||||
|
@ -144,6 +144,16 @@ typedef struct {
|
||||
GUID_DEF(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
|
||||
#define EFI_CUSTOM_MODE_ENABLE_GUID \
|
||||
GUID_DEF(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f)
|
||||
#define EFI_SYSTEM_RESOURCE_TABLE_GUID \
|
||||
GUID_DEF(0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80)
|
||||
|
||||
/* EFI System Resource Table (ESRT) Firmware Type Definitions */
|
||||
#define ESRT_FW_TYPE_UNKNOWN 0x00000000
|
||||
#define ESRT_FW_TYPE_SYSTEMFIRMWARE 0x00000001
|
||||
#define ESRT_FW_TYPE_DEVICEFIRMWARE 0x00000002
|
||||
#define ESRT_FW_TYPE_UEFIDRIVER 0x00000003
|
||||
|
||||
#define LAST_ATTEMPT_STATUS_SUCCESS 0x00000000
|
||||
|
||||
#define EVT_TIMER 0x80000000U
|
||||
#define EVT_RUNTIME 0x40000000U
|
||||
@ -458,6 +468,22 @@ typedef struct {
|
||||
} *ConfigurationTable;
|
||||
} EFI_SYSTEM_TABLE;
|
||||
|
||||
typedef struct {
|
||||
EFI_GUID FwClass;
|
||||
uint32_t FwType;
|
||||
uint32_t FwVersion;
|
||||
uint32_t LowestSupportedFwVersion;
|
||||
uint32_t CapsuleFlags;
|
||||
uint32_t LastAttemptVersion;
|
||||
uint32_t LastAttemptStatus;
|
||||
} EFI_SYSTEM_RESOURCE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
uint32_t FwResourceCount;
|
||||
uint32_t FwResourceCountMax;
|
||||
uint64_t FwResourceVersion;
|
||||
} EFI_SYSTEM_RESOURCE_TABLE;
|
||||
|
||||
extern EFI_SYSTEM_TABLE *ST;
|
||||
extern EFI_BOOT_SERVICES *BS;
|
||||
extern EFI_RUNTIME_SERVICES *RT;
|
||||
|
@ -267,6 +267,7 @@ libefi_sources = files(
|
||||
'measure.c',
|
||||
'part-discovery.c',
|
||||
'pe.c',
|
||||
'recovery.c',
|
||||
'random-seed.c',
|
||||
'secure-boot.c',
|
||||
'shim.c',
|
||||
|
23
src/boot/efi/recovery.c
Normal file
23
src/boot/efi/recovery.c
Normal file
@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "recovery.h"
|
||||
#include "util.h"
|
||||
|
||||
#define FALLBACK_BOOT_ENTRY L"ostree-1-lmp.conf\0"
|
||||
|
||||
bool recovery_check_firmware_failure(void) {
|
||||
EFI_SYSTEM_RESOURCE_TABLE *esrt_table = NULL;
|
||||
EFI_SYSTEM_RESOURCE_ENTRY *esrt_entry = NULL;
|
||||
|
||||
esrt_table = find_configuration_table(MAKE_GUID_PTR(EFI_SYSTEM_RESOURCE_TABLE));
|
||||
if (esrt_table) {
|
||||
esrt_entry = (void *)(esrt_table + 1);
|
||||
for (uint32_t i = 0; i < esrt_table->FwResourceCount; i++, esrt_entry++) {
|
||||
if (esrt_entry->FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) {
|
||||
return (esrt_entry->LastAttemptStatus != LAST_ATTEMPT_STATUS_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
7
src/boot/efi/recovery.h
Normal file
7
src/boot/efi/recovery.h
Normal file
@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <efi.h>
|
||||
#include "efivars-fundamental.h"
|
||||
|
||||
bool recovery_check_firmware_failure(void);
|
@ -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