]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-boot: allow setting the `timeout` via SMBIOS 11
authorMichael Vogt <michael.vogt@gmail.com>
Wed, 14 Jan 2026 12:09:10 +0000 (13:09 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 16 Jan 2026 09:26:48 +0000 (10:26 +0100)
Allow configuring the menu timeout used by sd-boot by setting
`io.systemd.boot.timeout=<value>` as SMBIOS type 11 string.

This takes precedence over the setting from the config file
and the EFI var.

Useful for e.g. integration tests that want to control that
a generic image boots faster.

man/smbios-type-11.xml
src/boot/boot.c

index 70f66fe0f61eee9e07da44b47b50dcff41718443..95754333a88187aa4beb6d64b05e21073630e783 100644 (file)
 
         <xi:include href="version-info.xml" xpointer="v259"/></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>io.systemd.boot.timeout=</varname><replaceable>TIMEOUT</replaceable></term>
+
+        <listitem><para>This allows configuration of the menu timeout in seconds, and is read by <command>systemd-boot</command>.
+        For details see
+        <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
+
+        <xi:include href="version-info.xml" xpointer="v260"/></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index b8a9264a496d92aedc33ba9cb01780dc7c1b9c9b..23aa36b3d16beb72294e658b99872c1c51b119da 100644 (file)
@@ -128,7 +128,8 @@ typedef struct {
         size_t n_entries;
         size_t idx_default;
         size_t idx_default_efivar;
-        uint64_t timeout_sec; /* Actual timeout used (efi_main() override > efivar > config). */
+        uint64_t timeout_sec; /* Actual timeout used (efi_main() override > smbios > efivar > config). */
+        uint64_t timeout_sec_smbios;
         uint64_t timeout_sec_config;
         uint64_t timeout_sec_efivar;
         char16_t *entry_default_config;
@@ -323,6 +324,7 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
 
         print_timeout_status("              timeout (config)", config->timeout_sec_config);
         print_timeout_status("             timeout (EFI var)", config->timeout_sec_efivar);
+        print_timeout_status("              timeout (smbios)", config->timeout_sec_smbios);
 
         if (config->entry_default_config)
                 printf("              default (config): %ls\n", config->entry_default_config);
@@ -1006,6 +1008,41 @@ static BootEntry* boot_entry_free(BootEntry *entry) {
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(BootEntry *, boot_entry_free);
 
+static EFI_STATUS config_timeout_sec_from_string(const char *value, uint64_t *dst) {
+        if (streq8(value, "menu-disabled"))
+                *dst = TIMEOUT_MENU_DISABLED;
+        else if (streq8(value, "menu-force"))
+                *dst = TIMEOUT_MENU_DISABLED;
+        else if (streq8(value, "menu-hidden"))
+                *dst = TIMEOUT_MENU_DISABLED;
+        else {
+                uint64_t u;
+                if (!parse_number8(value, &u, NULL) || u > TIMEOUT_TYPE_MAX)
+                        return EFI_INVALID_PARAMETER;
+                *dst = u;
+        }
+        return EFI_SUCCESS;
+}
+
+static void config_timeout_load_from_smbios(Config *config) {
+        EFI_STATUS err;
+
+        if (is_confidential_vm())
+                return; /* Don't consume SMBIOS in Confidential Computing contexts */
+
+        const char *value = smbios_find_oem_string("io.systemd.boot.timeout=", /* after= */ NULL);
+        if (!value)
+                return;
+
+        err = config_timeout_sec_from_string(value, &config->timeout_sec_smbios);
+        if (err != EFI_SUCCESS) {
+                log_warning_status(err, "Error parsing 'timeout' smbios option, ignoring: %s",
+                                   value);
+                return;
+        }
+        config->timeout_sec = config->timeout_sec_smbios;
+}
+
 static void config_defaults_load_from_file(Config *config, char *content) {
         char *line;
         size_t pos = 0;
@@ -1018,20 +1055,11 @@ static void config_defaults_load_from_file(Config *config, char *content) {
          * shared/bootspec.c@boot_loader_read_conf() to make parsing by bootctl/logind/etc. work. */
         while ((line = line_get_key_value(content, " \t", &pos, &key, &value)))
                 if (streq8(key, "timeout")) {
-                        if (streq8(value, "menu-disabled"))
-                                config->timeout_sec_config = TIMEOUT_MENU_DISABLED;
-                        else if (streq8(value, "menu-force"))
-                                config->timeout_sec_config = TIMEOUT_MENU_FORCE;
-                        else if (streq8(value, "menu-hidden"))
-                                config->timeout_sec_config = TIMEOUT_MENU_HIDDEN;
-                        else {
-                                uint64_t u;
-                                if (!parse_number8(value, &u, NULL) || u > TIMEOUT_TYPE_MAX) {
-                                        log_error("Error parsing 'timeout' config option, ignoring: %s",
-                                                  value);
-                                        continue;
-                                }
-                                config->timeout_sec_config = u;
+                        EFI_STATUS err = config_timeout_sec_from_string(value, &config->timeout_sec_config);
+                        if (err != EFI_SUCCESS) {
+                                log_warning_status(err, "Error parsing 'timeout' config option, ignoring: %s",
+                                                   value);
+                                continue;
                         }
                         config->timeout_sec = config->timeout_sec_config;
 
@@ -1496,6 +1524,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
                 .console_mode_efivar = CONSOLE_MODE_KEEP,
                 .timeout_sec_config = TIMEOUT_UNSET,
                 .timeout_sec_efivar = TIMEOUT_UNSET,
+                .timeout_sec_smbios = TIMEOUT_UNSET,
         };
 
         err = file_read(root_dir, u"\\loader\\loader.conf", 0, 0, &content, &content_size);
@@ -1520,6 +1549,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
                 config->timeout_sec = config->timeout_sec_efivar;
         else if (err != EFI_NOT_FOUND)
                 log_warning_status(err, "Error reading LoaderConfigTimeout EFI variable, ignoring: %m");
+        config_timeout_load_from_smbios(config);
 
         err = efivar_get_timeout(u"LoaderConfigTimeoutOneShot", &config->timeout_sec);
         if (err == EFI_SUCCESS) {