boot: Avoid magic values in timeout EFI vars

This commit is contained in:
Jan Janssen 2022-09-06 10:46:27 +02:00
parent 28fda21c85
commit 97f077df05
2 changed files with 51 additions and 10 deletions

View file

@ -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

View file

@ -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)