Linux EFI development
 help / color / mirror / Atom feed
* [PATCH v2] efi/libstub: populate LoaderDevicePartUUID
@ 2026-09-03 21:19 Vincent Mailhol
  2026-09-04 16:12 ` Ard Biesheuvel
  0 siblings, 1 reply; 4+ messages in thread
From: Vincent Mailhol @ 2026-09-03 21:19 UTC (permalink / raw)
  To: Ard Biesheuvel, Ilias Apalodimas; +Cc: linux-kernel, linux-efi, Vincent Mailhol

The Boot Loader Interface [1] defines LoaderDevicePartUUID. That EFI
variable records the GPT partition UUID of the partition containing the
boot loader.

This is used, for example, by systemd-gpt-auto-generator [2] to identify
the disk the boot loader was launched from and automatically detect and
mount partitions on it.

GRUB [3] and systemd-boot [4] populate it, but when the kernel is
started directly by EFI firmware, there is no conventional external boot
loader to provide the variable. In that case, because the EFI stub
performs the boot loader role, it should provide the variable itself.

Parse the loaded image device path, extract the GUID signature from its
GPT HD() node and publish it under the Linux loader entry vendor GUID as
the volatile LoaderDevicePartUUID EFI variable. Do not overwrite an
existing variable, so a value supplied by an earlier boot stage keeps
precedence.

Install the efi_bli_set_variables() hook in both the generic efi-stub.c
path and the x86-specific x86-stub.c path.

Add CONFIG_EFI_STUB_BLI to make this new feature configurable.

For an x86_64 build using gcc 15.3.0, bloat-o-meter reports the
following difference between builds without and with CONFIG_EFI_STUB_BLI:

  add/remove: 5/0 grow/shrink: 1/0 up/down: 639/0 (639)
  Function                                     old     new   delta
  efi_bli_set_variables                          -     563    +563
  loader_entry_guid                              -      16     +16
  hex                                            -      16     +16
  guid_index                                     -      16     +16
  device_path_guid                               -      16     +16
  efi_stub_entry                              4180    4192     +12
  Total: Before=29223, After=29862, chg +2.19%

[1] The Boot Loader Interface
Link: https://systemd.io/BOOT_LOADER_INTERFACE/

[2] systemd-gpt-auto-generator
Link: https://www.freedesktop.org/software/systemd/man/latest/systemd-gpt-auto-generator.html

[3] GRUB -- §16.2 bli
Link: https://www.gnu.org/software/grub/manual/grub/html_node/bli_005fmodule.html

[4] systemd -- systemd-boot UEFI Boot Manager
Link: https://github.com/systemd/systemd/blob/main/docs/BOOT.md?plain=1#L111

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
---
Changes in v2:

  - Add CONFIG_EFI_STUB_BLI to make the BLI feature optional.

  - Use static storage for GUID initializers. This reduces the size by
    about 10% compared to v1.

  - Remove the redundant NULL check on image.

  - Move the nibble-to-ASCII-hex conversion out of efi_bli_guid_to_str()
    into the new efi_bli_nibble_to_hex().

  - Rename variables to be closer to the EFI specification.

Link to v1: https://lore.kernel.org/r/20260725-efi_stub_bli-v1-1-966e4748077f@kernel.org
---
 drivers/firmware/efi/Kconfig            |  15 +++++
 drivers/firmware/efi/libstub/Makefile   |   2 +
 drivers/firmware/efi/libstub/bli.c      | 114 ++++++++++++++++++++++++++++++++
 drivers/firmware/efi/libstub/efi-stub.c |   1 +
 drivers/firmware/efi/libstub/efistub.h  |   6 ++
 drivers/firmware/efi/libstub/x86-stub.c |   1 +
 6 files changed, 139 insertions(+)

diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 29e0729299f5..eff7c6164096 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -100,6 +100,21 @@ config EFI_ARMSTUB_DTB_LOADER
 	  functionality for bootloaders that do not have such support
 	  this option is necessary.
 
+config EFI_STUB_BLI
+	bool "EFI stub Boot Loader Interface support"
+	depends on EFI_STUB
+	default y
+	help
+	  The Boot Loader Interface defines EFI variables that expose
+	  information about the boot loader to the running OS.
+
+	  Enable this option to let the EFI stub populate the volatile
+	  LoaderDevicePartUUID EFI variable when it is missing. This allows
+	  user space services such as systemd-gpt-auto-generator to discover
+	  partitions on the disk from which the kernel was loaded.
+
+	  If unsure, say Y.
+
 config EFI_BOOTLOADER_CONTROL
 	tristate "EFI Bootloader Control"
 	select UCS2_STRING
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 77a2b2d74f3f..000a73a4bc52 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -75,6 +75,8 @@ libfdt-deps			:= fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \
 lib-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdt.o \
 				     $(patsubst %.c,lib-%.o,$(libfdt-deps))
 
+lib-$(CONFIG_EFI_STUB_BLI)	+= bli.o
+
 $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
 	$(call if_changed_rule,cc_o_c)
 
diff --git a/drivers/firmware/efi/libstub/bli.c b/drivers/firmware/efi/libstub/bli.c
new file mode 100644
index 000000000000..d54eb42729a7
--- /dev/null
+++ b/drivers/firmware/efi/libstub/bli.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <linux/errno.h>
+#include <linux/unaligned.h>
+
+#include "efistub.h"
+
+struct efi_hd_dev_path {
+	struct efi_generic_dev_path header;
+	u32 partition_number;
+	u64 partition_start;
+	u64 partition_size;
+	efi_guid_t signature;
+	u8 partition_format;
+	u8 signature_type;
+} __packed;
+
+#define EFI_HD_PARTITION_FORMAT_GPT	2
+#define EFI_HD_SIGNATURE_TYPE_GUID	2
+
+static efi_char16_t efi_bli_nibble_to_hex(u8 nibble)
+{
+	static const char hex[16] __nonstring = "0123456789abcdef";
+
+	return hex[nibble];
+}
+
+static void efi_bli_guid_to_str(const efi_guid_t *guid, efi_char16_t *out)
+{
+	static const u8 guid_index[UUID_SIZE] = {
+		3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15,
+	};
+
+	for (int i = 0; i < ARRAY_SIZE(guid_index); i++) {
+		u8 byte = guid->b[guid_index[i]];
+
+		*out++ = efi_bli_nibble_to_hex(byte >> 4);
+		*out++ = efi_bli_nibble_to_hex(byte & 0xf);
+
+		switch (i) {
+		case 3:
+		case 5:
+		case 7:
+		case 9:
+			*out++ = L'-';
+		}
+	}
+
+	*out = L'\0';
+}
+
+static int efi_bli_dev_path_part_uuid(const efi_device_path_protocol_t *path,
+				      efi_char16_t *partuuid)
+{
+	const efi_device_path_protocol_t *node;
+	const struct efi_hd_dev_path *hd_node;
+	u16 node_len;
+
+	for (node = path;
+	     node->type != EFI_DEV_END_PATH && node->type != EFI_DEV_END_PATH2;
+	     node = (const void *)node + node_len) {
+		node_len = get_unaligned_le16(&node->length);
+
+		if (node_len < sizeof(*node))
+			return -EINVAL;
+
+		if (node->type != EFI_DEV_MEDIA ||
+		    node->sub_type != EFI_DEV_MEDIA_HARD_DRIVE)
+			continue;
+
+		if (node_len < sizeof(*hd_node))
+			return -EINVAL;
+
+		hd_node = (const struct efi_hd_dev_path *)node;
+		if (hd_node->partition_format != EFI_HD_PARTITION_FORMAT_GPT ||
+		    hd_node->signature_type != EFI_HD_SIGNATURE_TYPE_GUID)
+			continue;
+
+		efi_bli_guid_to_str(&hd_node->signature, partuuid);
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+static void efi_bli_populate_loader_part_uuid(efi_loaded_image_t *image)
+{
+	static efi_guid_t device_path_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
+	static efi_guid_t loader_entry_guid = LINUX_EFI_LOADER_ENTRY_GUID;
+	efi_char16_t partuuid[UUID_STRING_LEN + 1];
+	unsigned long size = 0;
+	void *path;
+
+	if (get_efi_var(L"LoaderDevicePartUUID", &loader_entry_guid,
+			NULL, &size, NULL) != EFI_NOT_FOUND)
+		return;
+
+	if (efi_bs_call(handle_protocol, efi_table_attr(image, device_handle),
+			&device_path_guid, &path) != EFI_SUCCESS)
+		return;
+
+	if (efi_bli_dev_path_part_uuid(path, partuuid))
+		return;
+
+	set_efi_var(L"LoaderDevicePartUUID", &loader_entry_guid,
+		    EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+		    sizeof(partuuid), partuuid);
+}
+
+void efi_bli_set_variables(efi_loaded_image_t *image)
+{
+	efi_bli_populate_loader_part_uuid(image);
+}
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index 42d6073bcd06..2a95f4ea104a 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -165,6 +165,7 @@ efi_status_t efi_stub_common(efi_handle_t handle,
 	dpy = setup_primary_display();
 
 	efi_retrieve_eventlog();
+	efi_bli_set_variables(image);
 
 	/* Ask the firmware to clear memory on unclean shutdown */
 	efi_enable_reset_attack_mitigation();
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index fd91fc15ec81..a4f961ea43a8 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -1072,6 +1072,12 @@ efi_status_t efi_random_alloc(unsigned long size, unsigned long align,
 			      int memory_type, unsigned long alloc_min,
 			      unsigned long alloc_max);
 
+#ifdef CONFIG_EFI_STUB_BLI
+void efi_bli_set_variables(efi_loaded_image_t *image);
+#else
+static inline void efi_bli_set_variables(efi_loaded_image_t *image) { }
+#endif
+
 efi_status_t efi_random_get_seed(void);
 
 efi_status_t check_platform_features(void);
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index cef32e2c82d8..b762f7f37f28 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -1014,6 +1014,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
 	efi_random_get_seed();
 
 	efi_retrieve_eventlog();
+	efi_bli_set_variables(image);
 
 	setup_graphics(boot_params);
 

---
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
change-id: 20260724-efi_stub_bli-477289050225

Best regards,
--  
Vincent Mailhol <mailhol@kernel.org>


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] efi/libstub: populate LoaderDevicePartUUID
  2026-09-03 21:19 [PATCH v2] efi/libstub: populate LoaderDevicePartUUID Vincent Mailhol
@ 2026-09-04 16:12 ` Ard Biesheuvel
  2026-09-04 22:06   ` Vincent Mailhol
  0 siblings, 1 reply; 4+ messages in thread
From: Ard Biesheuvel @ 2026-09-04 16:12 UTC (permalink / raw)
  To: Vincent Mailhol, Ilias Apalodimas; +Cc: linux-kernel, linux-efi

Hello Vincent,

On Thu, 3 Sep 2026, at 23:19, Vincent Mailhol wrote:
> The Boot Loader Interface [1] defines LoaderDevicePartUUID. That EFI
> variable records the GPT partition UUID of the partition containing the
> boot loader.
>
> This is used, for example, by systemd-gpt-auto-generator [2] to identify
> the disk the boot loader was launched from and automatically detect and
> mount partitions on it.
>
> GRUB [3] and systemd-boot [4] populate it, but when the kernel is
> started directly by EFI firmware, there is no conventional external boot
> loader to provide the variable. In that case, because the EFI stub
> performs the boot loader role, it should provide the variable itself.
>

Fair enough.

But shouldn't it set LoaderInfo as well then?

> Parse the loaded image device path, extract the GUID signature from its
> GPT HD() node and publish it under the Linux loader entry vendor GUID as
> the volatile LoaderDevicePartUUID EFI variable. Do not overwrite an
> existing variable, so a value supplied by an earlier boot stage keeps
> precedence.
>
> Install the efi_bli_set_variables() hook in both the generic efi-stub.c
> path and the x86-specific x86-stub.c path.
>
> Add CONFIG_EFI_STUB_BLI to make this new feature configurable.
>

I don't think this is needed tbh. Better to enable this unconditionally
so we can rely on this being present in the longer term.

> For an x86_64 build using gcc 15.3.0, bloat-o-meter reports the
> following difference between builds without and with CONFIG_EFI_STUB_BLI:
>
>   add/remove: 5/0 grow/shrink: 1/0 up/down: 639/0 (639)
>   Function                                     old     new   delta
>   efi_bli_set_variables                          -     563    +563
>   loader_entry_guid                              -      16     +16
>   hex                                            -      16     +16
>   guid_index                                     -      16     +16
>   device_path_guid                               -      16     +16
>   efi_stub_entry                              4180    4192     +12
>   Total: Before=29223, After=29862, chg +2.19%
>
> [1] The Boot Loader Interface
> Link: https://systemd.io/BOOT_LOADER_INTERFACE/
>
> [2] systemd-gpt-auto-generator
> Link: 
> https://www.freedesktop.org/software/systemd/man/latest/systemd-gpt-auto-generator.html
>
> [3] GRUB -- §16.2 bli
> Link: 
> https://www.gnu.org/software/grub/manual/grub/html_node/bli_005fmodule.html
>
> [4] systemd -- systemd-boot UEFI Boot Manager
> Link: https://github.com/systemd/systemd/blob/main/docs/BOOT.md?plain=1#L111
>
> Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
> ---
> Changes in v2:
>
>   - Add CONFIG_EFI_STUB_BLI to make the BLI feature optional.
>
>   - Use static storage for GUID initializers. This reduces the size by
>     about 10% compared to v1.
>
>   - Remove the redundant NULL check on image.
>
>   - Move the nibble-to-ASCII-hex conversion out of efi_bli_guid_to_str()
>     into the new efi_bli_nibble_to_hex().
>
>   - Rename variables to be closer to the EFI specification.
>
> Link to v1: 
> https://lore.kernel.org/r/20260725-efi_stub_bli-v1-1-966e4748077f@kernel.org
> ---
>  drivers/firmware/efi/Kconfig            |  15 +++++
>  drivers/firmware/efi/libstub/Makefile   |   2 +
>  drivers/firmware/efi/libstub/bli.c      | 114 
> ++++++++++++++++++++++++++++++++
>  drivers/firmware/efi/libstub/efi-stub.c |   1 +
>  drivers/firmware/efi/libstub/efistub.h  |   6 ++
>  drivers/firmware/efi/libstub/x86-stub.c |   1 +
>  6 files changed, 139 insertions(+)
>
> diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> index 29e0729299f5..eff7c6164096 100644
> --- a/drivers/firmware/efi/Kconfig
> +++ b/drivers/firmware/efi/Kconfig
> @@ -100,6 +100,21 @@ config EFI_ARMSTUB_DTB_LOADER
>  	  functionality for bootloaders that do not have such support
>  	  this option is necessary.
> 
> +config EFI_STUB_BLI
> +	bool "EFI stub Boot Loader Interface support"
> +	depends on EFI_STUB
> +	default y
> +	help
> +	  The Boot Loader Interface defines EFI variables that expose
> +	  information about the boot loader to the running OS.
> +
> +	  Enable this option to let the EFI stub populate the volatile
> +	  LoaderDevicePartUUID EFI variable when it is missing. This allows
> +	  user space services such as systemd-gpt-auto-generator to discover
> +	  partitions on the disk from which the kernel was loaded.
> +
> +	  If unsure, say Y.
> +
>  config EFI_BOOTLOADER_CONTROL
>  	tristate "EFI Bootloader Control"
>  	select UCS2_STRING
> diff --git a/drivers/firmware/efi/libstub/Makefile 
> b/drivers/firmware/efi/libstub/Makefile
> index 77a2b2d74f3f..000a73a4bc52 100644
> --- a/drivers/firmware/efi/libstub/Makefile
> +++ b/drivers/firmware/efi/libstub/Makefile
> @@ -75,6 +75,8 @@ libfdt-deps			:= fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \
>  lib-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdt.o \
>  				     $(patsubst %.c,lib-%.o,$(libfdt-deps))
> 
> +lib-$(CONFIG_EFI_STUB_BLI)	+= bli.o
> +
>  $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
>  	$(call if_changed_rule,cc_o_c)
> 
> diff --git a/drivers/firmware/efi/libstub/bli.c 
> b/drivers/firmware/efi/libstub/bli.c
> new file mode 100644
> index 000000000000..d54eb42729a7
> --- /dev/null
> +++ b/drivers/firmware/efi/libstub/bli.c
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/efi.h>
> +#include <linux/errno.h>
> +#include <linux/unaligned.h>
> +
> +#include "efistub.h"
> +
> +struct efi_hd_dev_path {
> +	struct efi_generic_dev_path header;
> +	u32 partition_number;
> +	u64 partition_start;
> +	u64 partition_size;
> +	efi_guid_t signature;
> +	u8 partition_format;
> +	u8 signature_type;
> +} __packed;
> +

Please add this to linux/efi.h and add it to the union
in struct efi_dev_path as well.

> +#define EFI_HD_PARTITION_FORMAT_GPT	2
> +#define EFI_HD_SIGNATURE_TYPE_GUID	2
> +

These too

> +static efi_char16_t efi_bli_nibble_to_hex(u8 nibble)
> +{
> +	static const char hex[16] __nonstring = "0123456789abcdef";
> +
> +	return hex[nibble];
> +}
> +
> +static void efi_bli_guid_to_str(const efi_guid_t *guid, efi_char16_t 
> *out)
> +{
> +	static const u8 guid_index[UUID_SIZE] = {
> +		3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15,
> +	};
> +
> +	for (int i = 0; i < ARRAY_SIZE(guid_index); i++) {
> +		u8 byte = guid->b[guid_index[i]];
> +
> +		*out++ = efi_bli_nibble_to_hex(byte >> 4);
> +		*out++ = efi_bli_nibble_to_hex(byte & 0xf);
> +
> +		switch (i) {
> +		case 3:
> +		case 5:
> +		case 7:
> +		case 9:
> +			*out++ = L'-';
> +		}
> +	}
> +
> +	*out = L'\0';
> +}
> +

I'm reluctant to add this kind of code as a special one-off, so I got a
bit carried away and took this code and put it in the stub's printf
layer.

Could you please check whether the first two patches at [0] are
sufficient for efi_bli_guid_to_str() to be replaced by a simple
efi_snprintf("%pUl", ...) call here?


-- 
Ard.


[0] https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-native-utf16


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] efi/libstub: populate LoaderDevicePartUUID
  2026-09-04 16:12 ` Ard Biesheuvel
@ 2026-09-04 22:06   ` Vincent Mailhol
  2026-09-05 12:05     ` Vincent Mailhol
  0 siblings, 1 reply; 4+ messages in thread
From: Vincent Mailhol @ 2026-09-04 22:06 UTC (permalink / raw)
  To: Ard Biesheuvel, Ilias Apalodimas; +Cc: linux-kernel, linux-efi

On 04/09/2026 at 18:12, Ard Biesheuvel wrote:
> Hello Vincent,
> 
> On Thu, 3 Sep 2026, at 23:19, Vincent Mailhol wrote:
>> The Boot Loader Interface [1] defines LoaderDevicePartUUID. That EFI
>> variable records the GPT partition UUID of the partition containing the
>> boot loader.
>>
>> This is used, for example, by systemd-gpt-auto-generator [2] to identify
>> the disk the boot loader was launched from and automatically detect and
>> mount partitions on it.
>>
>> GRUB [3] and systemd-boot [4] populate it, but when the kernel is
>> started directly by EFI firmware, there is no conventional external boot
>> loader to provide the variable. In that case, because the EFI stub
>> performs the boot loader role, it should provide the variable itself.
>>
> 
> Fair enough.
> 
> But shouldn't it set LoaderInfo as well then?

Sure. This is quite easy to do.

Any preference of what to put in that variable? I am thinking of
adding the release number like this:

	#define EFI_BLI_LOADER_INFO L"Linux EFI stub " UTS_RELEASE

This looks consistent with what the other boot loaders are doing:

	$ cat /sys/firmware/efi/efivars/LoaderInfo-4a67b082-0a4c-41cfb6c7-440b29bb8c4f 
	GRUB 2.12

Also, this gave me an idea. Maybe we can use the LoaderInfo variable
as a sentinel for all other variables:

	void efi_bli_set_variables(efi_loaded_image_t *image)
	{
		unsigned long size = 0;

		if (get_efi_var(L"LoaderInfo", &loader_entry_guid,
				NULL, &size, NULL) != EFI_NOT_FOUND)
			return;

		efi_bli_populate_loader_info();
		efi_bli_populate_loader_part_uuid(image);
	}

If it is set, we bail out, otherwise, we assume that the earlier boot
stage did not implement BLI and we blindly populate everything. No
more additional check on whether LoaderDevicePartUUID or other
variables are set!

Does this approach make sense?

>> Parse the loaded image device path, extract the GUID signature from its
>> GPT HD() node and publish it under the Linux loader entry vendor GUID as
>> the volatile LoaderDevicePartUUID EFI variable. Do not overwrite an
>> existing variable, so a value supplied by an earlier boot stage keeps
>> precedence.
>>
>> Install the efi_bli_set_variables() hook in both the generic efi-stub.c
>> path and the x86-specific x86-stub.c path.
>>
>> Add CONFIG_EFI_STUB_BLI to make this new feature configurable.
>>
> 
> I don't think this is needed tbh. Better to enable this unconditionally
> so we can rely on this being present in the longer term.

Agreed. To be honest, I did not put that in v1. I was just worried
that people might complain of the size increase for a feature some
might no want to use. But maybe my other cleanup series on the GUID
made a more convincing argument on the size!

I will happily remove this in v3.

>> For an x86_64 build using gcc 15.3.0, bloat-o-meter reports the
>> following difference between builds without and with CONFIG_EFI_STUB_BLI:
>>
>>   add/remove: 5/0 grow/shrink: 1/0 up/down: 639/0 (639)
>>   Function                                     old     new   delta
>>   efi_bli_set_variables                          -     563    +563
>>   loader_entry_guid                              -      16     +16
>>   hex                                            -      16     +16
>>   guid_index                                     -      16     +16
>>   device_path_guid                               -      16     +16
>>   efi_stub_entry                              4180    4192     +12
>>   Total: Before=29223, After=29862, chg +2.19%
>>
>> [1] The Boot Loader Interface
>> Link: https://systemd.io/BOOT_LOADER_INTERFACE/
>>
>> [2] systemd-gpt-auto-generator
>> Link: 
>> https://www.freedesktop.org/software/systemd/man/latest/systemd-gpt-auto-generator.html
>>
>> [3] GRUB -- §16.2 bli
>> Link: 
>> https://www.gnu.org/software/grub/manual/grub/html_node/bli_005fmodule.html
>>
>> [4] systemd -- systemd-boot UEFI Boot Manager
>> Link: https://github.com/systemd/systemd/blob/main/docs/BOOT.md?plain=1#L111
>>
>> Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
>> ---
>> Changes in v2:
>>
>>   - Add CONFIG_EFI_STUB_BLI to make the BLI feature optional.
>>
>>   - Use static storage for GUID initializers. This reduces the size by
>>     about 10% compared to v1.
>>
>>   - Remove the redundant NULL check on image.
>>
>>   - Move the nibble-to-ASCII-hex conversion out of efi_bli_guid_to_str()
>>     into the new efi_bli_nibble_to_hex().
>>
>>   - Rename variables to be closer to the EFI specification.
>>
>> Link to v1: 
>> https://lore.kernel.org/r/20260725-efi_stub_bli-v1-1-966e4748077f@kernel.org
>> ---
>>  drivers/firmware/efi/Kconfig            |  15 +++++
>>  drivers/firmware/efi/libstub/Makefile   |   2 +
>>  drivers/firmware/efi/libstub/bli.c      | 114 
>> ++++++++++++++++++++++++++++++++
>>  drivers/firmware/efi/libstub/efi-stub.c |   1 +
>>  drivers/firmware/efi/libstub/efistub.h  |   6 ++
>>  drivers/firmware/efi/libstub/x86-stub.c |   1 +
>>  6 files changed, 139 insertions(+)
>>
>> diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
>> index 29e0729299f5..eff7c6164096 100644
>> --- a/drivers/firmware/efi/Kconfig
>> +++ b/drivers/firmware/efi/Kconfig
>> @@ -100,6 +100,21 @@ config EFI_ARMSTUB_DTB_LOADER
>>  	  functionality for bootloaders that do not have such support
>>  	  this option is necessary.
>>
>> +config EFI_STUB_BLI
>> +	bool "EFI stub Boot Loader Interface support"
>> +	depends on EFI_STUB
>> +	default y
>> +	help
>> +	  The Boot Loader Interface defines EFI variables that expose
>> +	  information about the boot loader to the running OS.
>> +
>> +	  Enable this option to let the EFI stub populate the volatile
>> +	  LoaderDevicePartUUID EFI variable when it is missing. This allows
>> +	  user space services such as systemd-gpt-auto-generator to discover
>> +	  partitions on the disk from which the kernel was loaded.
>> +
>> +	  If unsure, say Y.
>> +
>>  config EFI_BOOTLOADER_CONTROL
>>  	tristate "EFI Bootloader Control"
>>  	select UCS2_STRING
>> diff --git a/drivers/firmware/efi/libstub/Makefile 
>> b/drivers/firmware/efi/libstub/Makefile
>> index 77a2b2d74f3f..000a73a4bc52 100644
>> --- a/drivers/firmware/efi/libstub/Makefile
>> +++ b/drivers/firmware/efi/libstub/Makefile
>> @@ -75,6 +75,8 @@ libfdt-deps			:= fdt_rw.c fdt_ro.c fdt_wip.c fdt.c \
>>  lib-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdt.o \
>>  				     $(patsubst %.c,lib-%.o,$(libfdt-deps))
>>
>> +lib-$(CONFIG_EFI_STUB_BLI)	+= bli.o
>> +
>>  $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
>>  	$(call if_changed_rule,cc_o_c)
>>
>> diff --git a/drivers/firmware/efi/libstub/bli.c 
>> b/drivers/firmware/efi/libstub/bli.c
>> new file mode 100644
>> index 000000000000..d54eb42729a7
>> --- /dev/null
>> +++ b/drivers/firmware/efi/libstub/bli.c
>> @@ -0,0 +1,114 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +#include <linux/efi.h>
>> +#include <linux/errno.h>
>> +#include <linux/unaligned.h>
>> +
>> +#include "efistub.h"
>> +
>> +struct efi_hd_dev_path {
>> +	struct efi_generic_dev_path header;
>> +	u32 partition_number;
>> +	u64 partition_start;
>> +	u64 partition_size;
>> +	efi_guid_t signature;
>> +	u8 partition_format;
>> +	u8 signature_type;
>> +} __packed;
>> +
> 
> Please add this to linux/efi.h and add it to the union
> in struct efi_dev_path as well.
> 
>> +#define EFI_HD_PARTITION_FORMAT_GPT	2
>> +#define EFI_HD_SIGNATURE_TYPE_GUID	2
>> +
> 
> These too

Ack.

>> +static efi_char16_t efi_bli_nibble_to_hex(u8 nibble)
>> +{
>> +	static const char hex[16] __nonstring = "0123456789abcdef";
>> +
>> +	return hex[nibble];
>> +}
>> +
>> +static void efi_bli_guid_to_str(const efi_guid_t *guid, efi_char16_t 
>> *out)
>> +{
>> +	static const u8 guid_index[UUID_SIZE] = {
>> +		3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15,
>> +	};
>> +
>> +	for (int i = 0; i < ARRAY_SIZE(guid_index); i++) {
>> +		u8 byte = guid->b[guid_index[i]];
>> +
>> +		*out++ = efi_bli_nibble_to_hex(byte >> 4);
>> +		*out++ = efi_bli_nibble_to_hex(byte & 0xf);
>> +
>> +		switch (i) {
>> +		case 3:
>> +		case 5:
>> +		case 7:
>> +		case 9:
>> +			*out++ = L'-';
>> +		}
>> +	}
>> +
>> +	*out = L'\0';
>> +}
>> +
> 
> I'm reluctant to add this kind of code as a special one-off, so I got a
> bit carried away and took this code and put it in the stub's printf
> layer.

Thanks for the extra work!

> Could you please check whether the first two patches at [0] are
> sufficient for efi_bli_guid_to_str() to be replaced by a simple
> efi_snprintf("%pUl", ...) call here?

Ack. I already rebased and did a compile test, OK so far. The runtime
test will come later. If I find an issue, I will send you a fix. If
not, I will just send the v3 rebased on top of your
efi-libstub-native-utf16 branch.


Yours sincerely,
Vincent Mailhol

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v2] efi/libstub: populate LoaderDevicePartUUID
  2026-09-04 22:06   ` Vincent Mailhol
@ 2026-09-05 12:05     ` Vincent Mailhol
  0 siblings, 0 replies; 4+ messages in thread
From: Vincent Mailhol @ 2026-09-05 12:05 UTC (permalink / raw)
  To: Ard Biesheuvel, Ilias Apalodimas; +Cc: linux-kernel, linux-efi

On 05/09/2026 at 00:06, Vincent Mailhol wrote:
> On 04/09/2026 at 18:12, Ard Biesheuvel wrote:
>> Hello Vincent,
>>
>> On Thu, 3 Sep 2026, at 23:19, Vincent Mailhol wrote:
>>> The Boot Loader Interface [1] defines LoaderDevicePartUUID. That EFI
>>> variable records the GPT partition UUID of the partition containing the
>>> boot loader.
>>>
>>> This is used, for example, by systemd-gpt-auto-generator [2] to identify
>>> the disk the boot loader was launched from and automatically detect and
>>> mount partitions on it.
>>>
>>> GRUB [3] and systemd-boot [4] populate it, but when the kernel is
>>> started directly by EFI firmware, there is no conventional external boot
>>> loader to provide the variable. In that case, because the EFI stub
>>> performs the boot loader role, it should provide the variable itself.
>>>
>>
>> Fair enough.
>>
>> But shouldn't it set LoaderInfo as well then?
> 
> Sure. This is quite easy to do.
> 
> Any preference of what to put in that variable? I am thinking of
> adding the release number like this:
> 
> 	#define EFI_BLI_LOADER_INFO L"Linux EFI stub " UTS_RELEASE
> 
> This looks consistent with what the other boot loaders are doing:
> 
> 	$ cat /sys/firmware/efi/efivars/LoaderInfo-4a67b082-0a4c-41cfb6c7-440b29bb8c4f 
> 	GRUB 2.12
> 
> Also, this gave me an idea. Maybe we can use the LoaderInfo variable
> as a sentinel for all other variables:
> 
> 	void efi_bli_set_variables(efi_loaded_image_t *image)
> 	{
> 		unsigned long size = 0;
> 
> 		if (get_efi_var(L"LoaderInfo", &loader_entry_guid,
> 				NULL, &size, NULL) != EFI_NOT_FOUND)
> 			return;
> 
> 		efi_bli_populate_loader_info();
> 		efi_bli_populate_loader_part_uuid(image);
> 	}
> 
> If it is set, we bail out, otherwise, we assume that the earlier boot
> stage did not implement BLI and we blindly populate everything. No
> more additional check on whether LoaderDevicePartUUID or other
> variables are set!

FYI, this is my latest WIP:

	void efi_bli_set_variables(efi_loaded_image_t *image)
	{
		static efi_char16_t loader_info[] = L"Linux EFI stub " UTS_RELEASE;
		unsigned long size = 0;
	
		if (get_efi_var(L"LoaderInfo", &loader_entry_guid,
				NULL, &size, NULL) != EFI_NOT_FOUND)
			return;
	
		if (set_efi_var(L"LoaderInfo", &loader_entry_guid,
				EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
				sizeof(loader_info), loader_info) != EFI_SUCCESS)
			return;
	
		efi_bli_populate_loader_part_uuid(image);
	}

The idea is that the sentinel check will not only be the presence of
LoaderInfo but also the fact that we could successfully set it. The
other variables (LoaderDevicePartUUID and whatever might comme in the
future) are set without further check and failure to set them is
silencely ignored.

> Does this approach make sense?

(...)

>> I'm reluctant to add this kind of code as a special one-off, so I got a
>> bit carried away and took this code and put it in the stub's printf
>> layer.
> 
> Thanks for the extra work!
> 
>> Could you please check whether the first two patches at [0] are
>> sufficient for efi_bli_guid_to_str() to be replaced by a simple
>> efi_snprintf("%pUl", ...) call here?
> 
> Ack. I already rebased and did a compile test, OK so far. The runtime
> test will come later. If I find an issue, I will send you a fix. If
> not, I will just send the v3 rebased on top of your
> efi-libstub-native-utf16 branch.

I spoke a bit too quick. Compiling

  drivers/firmware/efi/libstub/lib.a

worked well, but in a full build,

  arch/x86/boot/compressed/error.c

failed to link because it expects libstub to provide vsnprintf()
(c.f. comment above panic()) which you removed in commit edbd49dfea2a
("efi/libstub: Add widestring support to vsnprintf()").

You need to squash this in that commit:

---8<---
diff --git a/drivers/firmware/efi/libstub/vsprintf.c b/drivers/firmware/efi/libstub/vsprintf.c
index 521bdace031df..337326ce00488 100644
--- a/drivers/firmware/efi/libstub/vsprintf.c
+++ b/drivers/firmware/efi/libstub/vsprintf.c
@@ -663,6 +663,11 @@ int snprintf(char *buf, size_t size, const char *fmt, ...)
 	return i;
 }
 
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+	return efi_vsnprintf(buf, size, fmt, args, false, false);
+}
+
 int efi_snprintf(efi_char16_t *buf, size_t size, const char *fmt, ...)
 {
 	va_list args;
---8<---

or modify arch/x86/boot/compressed/error.c to take another vsnprintf()
variant.


Yours sincerely,
Vincent Mailhol

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-05 12:05 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 21:19 [PATCH v2] efi/libstub: populate LoaderDevicePartUUID Vincent Mailhol
2026-09-04 16:12 ` Ard Biesheuvel
2026-09-04 22:06   ` Vincent Mailhol
2026-09-05 12:05     ` Vincent Mailhol

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox