summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Janssen <medhefgo@web.de>2022-09-06 10:46:27 +0200
committerJan Janssen <medhefgo@web.de>2022-09-07 12:55:55 +0200
commit97f077df052c75224dcc73375bfaaa69af6a1c26 (patch)
treee6b284581b54cc4501b4820b61b16f5285e19d92
parentboot: Use proper scan codes (diff)
downloadsystemd-97f077df052c75224dcc73375bfaaa69af6a1c26.tar.xz
systemd-97f077df052c75224dcc73375bfaaa69af6a1c26.zip
boot: Avoid magic values in timeout EFI vars
-rw-r--r--docs/BOOT_LOADER_INTERFACE.md6
-rw-r--r--src/boot/efi/boot.c55
2 files changed, 51 insertions, 10 deletions
diff --git a/docs/BOOT_LOADER_INTERFACE.md b/docs/BOOT_LOADER_INTERFACE.md
index f7be50421c..fc9336085b 100644
--- a/docs/BOOT_LOADER_INTERFACE.md
+++ b/docs/BOOT_LOADER_INTERFACE.md
@@ -31,7 +31,11 @@ variables. All EFI variables use the vendor UUID
* The EFI variable `LoaderConfigTimeout` contains the boot menu timeout
currently in use. It may be modified both by the boot loader and by the
host. The value should be formatted as numeric, NUL-terminated, decimal
- string, in UTF-16. The time is specified in µs.
+ string, in UTF-16. The time is specified in seconds. A value of `menu-force`
+ will disable the timeout and show the menu indefinitely. If set to `0` or
+ `menu-hidden` the default entry is booted immediately without showing a menu.
+ The boot loader should provide a way to interrupt this by for example
+ listening for key presses for a brief moment before booting.
* Similarly, the EFI variable `LoaderConfigTimeoutOneShot` contains a boot menu
timeout for a single following boot. It is set by the OS in order to request
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index ac08650c29..a7ef57cb99 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -1037,11 +1037,20 @@ static bool menu_run(
}
if (timeout_efivar_saved != config->timeout_sec_efivar) {
- if (config->timeout_sec_efivar == TIMEOUT_UNSET)
+ switch (config->timeout_sec_efivar) {
+ case TIMEOUT_UNSET:
efivar_set(LOADER_GUID, L"LoaderConfigTimeout", NULL, EFI_VARIABLE_NON_VOLATILE);
- else
+ break;
+ case TIMEOUT_MENU_FORCE:
+ efivar_set(LOADER_GUID, u"LoaderConfigTimeout", u"menu-force", EFI_VARIABLE_NON_VOLATILE);
+ break;
+ case TIMEOUT_MENU_HIDDEN:
+ efivar_set(LOADER_GUID, u"LoaderConfigTimeout", u"menu-hidden", EFI_VARIABLE_NON_VOLATILE);
+ break;
+ default:
efivar_set_uint_string(LOADER_GUID, L"LoaderConfigTimeout",
config->timeout_sec_efivar, EFI_VARIABLE_NON_VOLATILE);
+ }
}
clear_screen(COLOR_NORMAL);
@@ -1532,6 +1541,34 @@ static void config_entry_add_type1(
TAKE_PTR(entry);
}
+static EFI_STATUS efivar_get_timeout(const char16_t *var, uint32_t *ret_value) {
+ _cleanup_free_ char16_t *value = NULL;
+ EFI_STATUS err;
+
+ assert(var);
+ assert(ret_value);
+
+ err = efivar_get(LOADER_GUID, var, &value);
+ if (err != EFI_SUCCESS)
+ return err;
+
+ if (streq16(value, u"menu-force")) {
+ *ret_value = TIMEOUT_MENU_FORCE;
+ return EFI_SUCCESS;
+ }
+ if (streq16(value, u"menu-hidden")) {
+ *ret_value = TIMEOUT_MENU_HIDDEN;
+ return EFI_SUCCESS;
+ }
+
+ uint64_t timeout;
+ if (!parse_number16(value, &timeout, NULL))
+ return EFI_INVALID_PARAMETER;
+
+ *ret_value = MIN(timeout, TIMEOUT_TYPE_MAX);
+ return EFI_SUCCESS;
+}
+
static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
_cleanup_free_ char *content = NULL;
UINTN value;
@@ -1557,20 +1594,20 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
if (err == EFI_SUCCESS)
config_defaults_load_from_file(config, content);
- err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeout", &value);
- if (err == EFI_SUCCESS) {
- config->timeout_sec_efivar = MIN(value, TIMEOUT_TYPE_MAX);
+ err = efivar_get_timeout(u"LoaderConfigTimeout", &config->timeout_sec_efivar);
+ if (err == EFI_SUCCESS)
config->timeout_sec = config->timeout_sec_efivar;
- }
+ else if (err != EFI_NOT_FOUND)
+ log_error_stall(u"Error reading LoaderConfigTimeout EFI variable: %r", err);
- err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeoutOneShot", &value);
+ err = efivar_get_timeout(u"LoaderConfigTimeoutOneShot", &config->timeout_sec);
if (err == EFI_SUCCESS) {
/* Unset variable now, after all it's "one shot". */
(void) efivar_set(LOADER_GUID, L"LoaderConfigTimeoutOneShot", NULL, EFI_VARIABLE_NON_VOLATILE);
- config->timeout_sec = MIN(value, TIMEOUT_TYPE_MAX);
config->force_menu = true; /* force the menu when this is set */
- }
+ } else if (err != EFI_NOT_FOUND)
+ log_error_stall(u"Error reading LoaderConfigTimeoutOneShot EFI variable: %r", err);
err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigConsoleMode", &value);
if (err == EFI_SUCCESS)