diff --git a/man/smbios-type-11.xml b/man/smbios-type-11.xml
index 4d78f612e7..b576677d27 100644
--- a/man/smbios-type-11.xml
+++ b/man/smbios-type-11.xml
@@ -74,6 +74,16 @@
+
+
+ io.systemd.boot-entries.extra:ID=DEFINITION
+
+ This allows inserting additional entries into the systemd-boot
+ menu. For details see
+ systemd-boot7
+
+
+
diff --git a/man/systemd-boot.xml b/man/systemd-boot.xml
index 22f3cdb4ca..6da2714581 100644
--- a/man/systemd-boot.xml
+++ b/man/systemd-boot.xml
@@ -594,6 +594,28 @@
+
+
+ io.systemd.boot-entries.extra:ID=DEFINITION
+
+ This allows inserting additional entries into the systemd-boot
+ menu. Take a pair of menu entry identifier and menu entry definition string. The former should be
+ suitable for use as a filename of a Boot Loader Specification Type #1 entry filename (note that it is
+ used for identification purposes only, no file of this name is actually accessed), the latter shall
+ follow the syntax of the contents of a Type #1 entry. Any menu entry defined this way is processed
+ and shown in pretty much the same way as a Type #1 entry read from the ESP or XBOOTLDR
+ partition. Example:
+
+ io.systemd.boot-entries.extra:fooos-current.conf=title FooOS (Current)
+uki-url http://example.com/somedir/fooos.efi
+
+ Note that this example contains a newline character. When generating this string from a shell
+ care must be taken to encode it correctly.
+
+ Pass multiple strings formatted this way to generate multiple menu entries.
+
+
+
diff --git a/src/boot/boot.c b/src/boot/boot.c
index 980fcff7c3..75f764bc4e 100644
--- a/src/boot/boot.c
+++ b/src/boot/boot.c
@@ -1464,7 +1464,6 @@ static void boot_entry_add_type1(
assert(config);
assert(device);
assert(root_dir);
- assert(path);
assert(file);
assert(content);
@@ -1607,7 +1606,8 @@ static void boot_entry_add_type1(
config_add_entry(config, entry);
- boot_entry_parse_tries(entry, path, file, u".conf");
+ if (path)
+ boot_entry_parse_tries(entry, path, file, u".conf");
TAKE_PTR(entry);
}
@@ -1717,6 +1717,19 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", &config->entry_saved);
}
+static bool valid_type1_filename(const char16_t *fname) {
+ assert(fname);
+
+ if (IN_SET(fname[0], u'.', u'\0'))
+ return false;
+ if (!endswith_no_case(fname, u".conf"))
+ return false;
+ if (startswith_no_case(fname, u"auto-"))
+ return false;
+
+ return true;
+}
+
static void config_load_type1_entries(
Config *config,
EFI_HANDLE *device,
@@ -1747,13 +1760,9 @@ static void config_load_type1_entries(
if (err != EFI_SUCCESS || !f)
break;
- if (f->FileName[0] == '.')
- continue;
if (FLAGS_SET(f->Attribute, EFI_FILE_DIRECTORY))
continue;
- if (!endswith_no_case(f->FileName, u".conf"))
- continue;
- if (startswith_no_case(f->FileName, u"auto-"))
+ if (!valid_type1_filename(f->FileName))
continue;
err = file_read(entries_dir,
@@ -1769,6 +1778,41 @@ static void config_load_type1_entries(
}
}
+static void config_load_smbios_entries(
+ Config *config,
+ EFI_HANDLE *device,
+ EFI_FILE *root_dir,
+ const char16_t *loaded_image_path) {
+
+ assert(config);
+ assert(device);
+ assert(root_dir);
+
+ /* Loads Boot Loader Type #1 entries from SMBIOS 11 */
+
+ if (is_confidential_vm())
+ return; /* Don't consume SMBIOS in CoCo contexts */
+
+ for (const char *after = NULL, *extra;; after = extra) {
+ extra = smbios_find_oem_string("io.systemd.boot.entries-extra:", after);
+ if (!extra)
+ break;
+
+ const char *eq = strchr8(extra, '=');
+ if (!eq)
+ continue;
+
+ _cleanup_free_ char16_t *fname = xstrn8_to_16(extra, eq - extra);
+ if (!valid_type1_filename(fname))
+ continue;
+
+ /* Make a copy, since boot_entry_add_type1() wants to modify it */
+ _cleanup_free_ char *contents = xstrdup8(eq + 1);
+
+ boot_entry_add_type1(config, device, root_dir, /* path= */ NULL, fname, contents, loaded_image_path);
+ }
+}
+
static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
int r;
@@ -2775,7 +2819,7 @@ static EFI_STATUS image_start(
_cleanup_free_ char16_t *options = xstrdup16(options_initrd ?: entry->options_implied ? NULL : entry->options);
if (entry->type == LOADER_LINUX && !is_confidential_vm()) {
- const char *extra = smbios_find_oem_string("io.systemd.boot.kernel-cmdline-extra");
+ const char *extra = smbios_find_oem_string("io.systemd.boot.kernel-cmdline-extra=", /* after= */ NULL);
if (extra) {
_cleanup_free_ char16_t *tmp = TAKE_PTR(options), *extra16 = xstr8_to_16(extra);
if (isempty(tmp))
@@ -2989,6 +3033,9 @@ static void config_load_all_entries(
/* Similar, but on any XBOOTLDR partition */
config_load_xbootldr(config, loaded_image->DeviceHandle);
+ /* Pick up entries defined via SMBIOS Type #11 */
+ config_load_smbios_entries(config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
+
/* Sort entries after version number */
sort_pointer_array((void **) config->entries, config->n_entries, (compare_pointer_func_t) boot_entry_compare);
diff --git a/src/boot/smbios.c b/src/boot/smbios.c
index e1bcd62e2c..184aca14ce 100644
--- a/src/boot/smbios.c
+++ b/src/boot/smbios.c
@@ -182,7 +182,7 @@ bool smbios_in_hypervisor(void) {
return FLAGS_SET(type0->bios_characteristics_ext[1], 1 << 4);
}
-const char* smbios_find_oem_string(const char *name) {
+const char* smbios_find_oem_string(const char *name, const char *after) {
uint64_t left;
assert(name);
@@ -199,9 +199,9 @@ const char* smbios_find_oem_string(const char *name) {
if (!e || e == p) /* Double NUL byte means we've reached the end of the OEM strings. */
break;
- const char *eq = startswith8(p, name);
- if (eq && *eq == '=')
- return eq + 1;
+ const char *suffix = startswith8(p, name);
+ if (suffix && (!after || suffix > after))
+ return suffix;
p = e + 1;
}
diff --git a/src/boot/smbios.h b/src/boot/smbios.h
index 83c3c43589..694ef568e6 100644
--- a/src/boot/smbios.h
+++ b/src/boot/smbios.h
@@ -5,7 +5,7 @@
bool smbios_in_hypervisor(void);
-const char* smbios_find_oem_string(const char *name);
+const char* smbios_find_oem_string(const char *name, const char *after);
typedef struct RawSmbiosInfo {
const char *manufacturer;
diff --git a/src/boot/stub.c b/src/boot/stub.c
index ac6c112459..4793391b06 100644
--- a/src/boot/stub.c
+++ b/src/boot/stub.c
@@ -783,7 +783,7 @@ static void cmdline_append_and_measure_smbios(char16_t **cmdline, int *parameter
if (is_confidential_vm())
return;
- const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra");
+ const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra=", /* after= */ NULL);
if (!extra)
return;