Skip to content

Commit 4f3a3b7

Browse files
committed
sd-boot: also read type #1 entries from SMBIOS Type #11
With this we can now do: systemd-vmspawn -n -i foobar.raw -s io.systemd.boot.entries-extra:particleos-current.conf=$'title ParticleOS Current\nuki-url http://example.com/somedir/uki.efi' Assuming sd-boot is available inside the ESP of foobar.raw a new item will show up in the boot menu that allows booting directly into the specified UKI.
1 parent fab0f6e commit 4f3a3b7

File tree

6 files changed

+93
-14
lines changed

6 files changed

+93
-14
lines changed

man/smbios-type-11.xml

+10
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@
7474

7575
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
7676
</varlistentry>
77+
78+
<varlistentry>
79+
<term><varname>io.systemd.boot-entries.extra:</varname><replaceable>ID=DEFINITION</replaceable></term>
80+
81+
<listitem><para>This allows inserting additional entries into the <command>systemd-boot</command>
82+
menu. For details see
83+
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry></para>
84+
85+
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
86+
</varlistentry>
7787
</variablelist>
7888
</refsect1>
7989

man/systemd-boot.xml

+22
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,28 @@
594594

595595
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
596596
</varlistentry>
597+
598+
<varlistentry>
599+
<term><varname>io.systemd.boot-entries.extra:</varname><replaceable>ID=DEFINITION</replaceable></term>
600+
601+
<listitem><para>This allows inserting additional entries into the <command>systemd-boot</command>
602+
menu. Take a pair of menu entry identifier and menu entry definition string. The former should be
603+
suitable for use as a filename of a Boot Loader Specification Type #1 entry filename (note that it is
604+
used for identification purposes only, no file of this name is actually accessed), the latter shall
605+
follow the syntax of the contents of a Type #1 entry. Any menu entry defined this way is processed
606+
and shown in pretty much the same way as a Type #1 entry read from the ESP or XBOOTLDR
607+
partition. Example:</para>
608+
609+
<programlisting>io.systemd.boot-entries.extra:fooos-current.conf=title FooOS (Current)
610+
uki-url http://example.com/somedir/fooos.efi</programlisting>
611+
612+
<para>Note that this example contains a newline character. When generating this string from a shell
613+
care must be taken to encode it correctly.</para>
614+
615+
<para>Pass multiple strings formatted this way to generate multiple menu entries.</para>
616+
617+
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
618+
</varlistentry>
597619
</variablelist>
598620
</refsect1>
599621

src/boot/boot.c

+55-8
Original file line numberDiff line numberDiff line change
@@ -1464,7 +1464,6 @@ static void boot_entry_add_type1(
14641464
assert(config);
14651465
assert(device);
14661466
assert(root_dir);
1467-
assert(path);
14681467
assert(file);
14691468
assert(content);
14701469

@@ -1607,7 +1606,8 @@ static void boot_entry_add_type1(
16071606

16081607
config_add_entry(config, entry);
16091608

1610-
boot_entry_parse_tries(entry, path, file, u".conf");
1609+
if (path)
1610+
boot_entry_parse_tries(entry, path, file, u".conf");
16111611
TAKE_PTR(entry);
16121612
}
16131613

@@ -1717,6 +1717,19 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
17171717
(void) efivar_get_str16(MAKE_GUID_PTR(LOADER), u"LoaderEntryLastBooted", &config->entry_saved);
17181718
}
17191719

1720+
static bool valid_type1_filename(const char16_t *fname) {
1721+
assert(fname);
1722+
1723+
if (IN_SET(fname[0], u'.', u'\0'))
1724+
return false;
1725+
if (!endswith_no_case(fname, u".conf"))
1726+
return false;
1727+
if (startswith_no_case(fname, u"auto-"))
1728+
return false;
1729+
1730+
return true;
1731+
}
1732+
17201733
static void config_load_type1_entries(
17211734
Config *config,
17221735
EFI_HANDLE *device,
@@ -1747,13 +1760,9 @@ static void config_load_type1_entries(
17471760
if (err != EFI_SUCCESS || !f)
17481761
break;
17491762

1750-
if (f->FileName[0] == '.')
1751-
continue;
17521763
if (FLAGS_SET(f->Attribute, EFI_FILE_DIRECTORY))
17531764
continue;
1754-
if (!endswith_no_case(f->FileName, u".conf"))
1755-
continue;
1756-
if (startswith_no_case(f->FileName, u"auto-"))
1765+
if (!valid_type1_filename(f->FileName))
17571766
continue;
17581767

17591768
err = file_read(entries_dir,
@@ -1769,6 +1778,41 @@ static void config_load_type1_entries(
17691778
}
17701779
}
17711780

1781+
static void config_load_smbios_entries(
1782+
Config *config,
1783+
EFI_HANDLE *device,
1784+
EFI_FILE *root_dir,
1785+
const char16_t *loaded_image_path) {
1786+
1787+
assert(config);
1788+
assert(device);
1789+
assert(root_dir);
1790+
1791+
/* Loads Boot Loader Type #1 entries from SMBIOS 11 */
1792+
1793+
if (is_confidential_vm())
1794+
return; /* Don't consume SMBIOS in CoCo contexts */
1795+
1796+
for (const char *after = NULL, *extra;; after = extra) {
1797+
extra = smbios_find_oem_string("io.systemd.boot.entries-extra:", after);
1798+
if (!extra)
1799+
break;
1800+
1801+
const char *eq = strchr8(extra, '=');
1802+
if (!eq)
1803+
continue;
1804+
1805+
_cleanup_free_ char16_t *fname = xstrn8_to_16(extra, eq - extra);
1806+
if (!valid_type1_filename(fname))
1807+
continue;
1808+
1809+
/* Make a copy, since boot_entry_add_type1() wants to modify it */
1810+
_cleanup_free_ char *contents = xstrdup8(eq + 1);
1811+
1812+
boot_entry_add_type1(config, device, root_dir, /* path= */ NULL, fname, contents, loaded_image_path);
1813+
}
1814+
}
1815+
17721816
static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
17731817
int r;
17741818

@@ -2775,7 +2819,7 @@ static EFI_STATUS image_start(
27752819
_cleanup_free_ char16_t *options = xstrdup16(options_initrd ?: entry->options_implied ? NULL : entry->options);
27762820

27772821
if (entry->type == LOADER_LINUX && !is_confidential_vm()) {
2778-
const char *extra = smbios_find_oem_string("io.systemd.boot.kernel-cmdline-extra");
2822+
const char *extra = smbios_find_oem_string("io.systemd.boot.kernel-cmdline-extra=", /* after= */ NULL);
27792823
if (extra) {
27802824
_cleanup_free_ char16_t *tmp = TAKE_PTR(options), *extra16 = xstr8_to_16(extra);
27812825
if (isempty(tmp))
@@ -2989,6 +3033,9 @@ static void config_load_all_entries(
29893033
/* Similar, but on any XBOOTLDR partition */
29903034
config_load_xbootldr(config, loaded_image->DeviceHandle);
29913035

3036+
/* Pick up entries defined via SMBIOS Type #11 */
3037+
config_load_smbios_entries(config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
3038+
29923039
/* Sort entries after version number */
29933040
sort_pointer_array((void **) config->entries, config->n_entries, (compare_pointer_func_t) boot_entry_compare);
29943041

src/boot/smbios.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ bool smbios_in_hypervisor(void) {
182182
return FLAGS_SET(type0->bios_characteristics_ext[1], 1 << 4);
183183
}
184184

185-
const char* smbios_find_oem_string(const char *name) {
185+
const char* smbios_find_oem_string(const char *name, const char *after) {
186186
uint64_t left;
187187

188188
assert(name);
@@ -199,9 +199,9 @@ const char* smbios_find_oem_string(const char *name) {
199199
if (!e || e == p) /* Double NUL byte means we've reached the end of the OEM strings. */
200200
break;
201201

202-
const char *eq = startswith8(p, name);
203-
if (eq && *eq == '=')
204-
return eq + 1;
202+
const char *suffix = startswith8(p, name);
203+
if (suffix && (!after || suffix > after))
204+
return suffix;
205205

206206
p = e + 1;
207207
}

src/boot/smbios.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
bool smbios_in_hypervisor(void);
77

8-
const char* smbios_find_oem_string(const char *name);
8+
const char* smbios_find_oem_string(const char *name, const char *after);
99

1010
typedef struct RawSmbiosInfo {
1111
const char *manufacturer;

src/boot/stub.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,7 @@ static void cmdline_append_and_measure_smbios(char16_t **cmdline, int *parameter
783783
if (is_confidential_vm())
784784
return;
785785

786-
const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra");
786+
const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra=", /* after= */ NULL);
787787
if (!extra)
788788
return;
789789

0 commit comments

Comments
 (0)