[PATCH v1 27/54] efi: loader: add EFI load option handling

Ahmad Fatoum a.fatoum at pengutronix.de
Thu Dec 18 02:37:47 PST 2025


Import the load option utility functions from U-Boot, so barebox can
pass along the kernel command line.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 efi/loader/Makefile         |   1 +
 efi/loader/loadopts.c       | 181 ++++++++++++++++++++++++++++++++++++
 include/efi/loader/option.h |  36 +++++++
 3 files changed, 218 insertions(+)
 create mode 100644 efi/loader/loadopts.c
 create mode 100644 include/efi/loader/option.h

diff --git a/efi/loader/Makefile b/efi/loader/Makefile
index bb6aa05c3748..44ba3a86e4d4 100644
--- a/efi/loader/Makefile
+++ b/efi/loader/Makefile
@@ -11,3 +11,4 @@ obj-y += runtime.o
 obj-y += setup.o
 obj-y += watchdog.o
 obj-y += pe.o
+obj-y += loadopts.o
diff --git a/efi/loader/loadopts.c b/efi/loader/loadopts.c
new file mode 100644
index 000000000000..388b8bf699c4
--- /dev/null
+++ b/efi/loader/loadopts.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/c38cb227d39f8ce9983df8051f31dcc8466f311e/lib/efi_loader/efi_load_options.c
+/*
+ *  EFI boot manager
+ *
+ *  Copyright (c) 2018 AKASHI Takahiro, et.al.
+ */
+
+#define pr_fmt(fmt) "efi-loader: loadopts: " fmt
+
+#include <charset.h>
+#include <malloc.h>
+#include <efi/loader.h>
+#include <efi/loader/object.h>
+#include <efi/loader/option.h>
+#include <efi/error.h>
+#include <efi/guid.h>
+#include <efi/devicepath.h>
+#include <asm/unaligned.h>
+
+/**
+ * efi_set_load_options() - set the load options of a loaded image
+ *
+ * @handle:		the image handle
+ * @load_options_size:	size of load options
+ * @load_options:	pointer to load options
+ * Return:		status code
+ */
+efi_status_t efi_set_load_options(efi_handle_t handle,
+				  efi_uintn_t load_options_size,
+				  void *load_options)
+{
+	struct efi_loaded_image *loaded_image_info;
+	struct efi_handler *handler;
+	efi_status_t ret;
+
+	ret = efi_search_protocol(handle, &efi_loaded_image_protocol_guid, &handler);
+	if (ret != EFI_SUCCESS)
+		return EFI_INVALID_PARAMETER;
+
+	loaded_image_info = handler->protocol_interface;
+	loaded_image_info->load_options = load_options;
+	loaded_image_info->load_options_size = load_options_size;
+
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_dp_check_length() - check length of a device path
+ *
+ * @dp:		pointer to device path
+ * @maxlen:	maximum length of the device path
+ * Return:
+ * * length of the device path if it is less or equal @maxlen
+ * * -1 if the device path is longer then @maxlen
+ * * -1 if a device path node has a length of less than 4
+ * * -EINVAL if maxlen exceeds SSIZE_MAX
+ */
+static ssize_t efi_dp_check_length(const struct efi_device_path *dp,
+				   const size_t maxlen)
+{
+	ssize_t ret = 0;
+	u16 len;
+
+	if (maxlen > SSIZE_MAX)
+		return -EINVAL;
+	for (;;) {
+		len = dp->length;
+		if (len < 4)
+			return -1;
+		ret += len;
+		if (ret > maxlen)
+			return -1;
+		if (dp->type == DEVICE_PATH_TYPE_END &&
+		    dp->sub_type == DEVICE_PATH_SUB_TYPE_END)
+			return ret;
+		dp = (const struct efi_device_path *)((const u8 *)dp + len);
+	}
+}
+
+/**
+ * efi_deserialize_load_option() - parse serialized data
+ *
+ * Parse serialized data describing a load option and transform it to the
+ * efi_load_option structure.
+ *
+ * @lo:		pointer to target
+ * @data:	serialized data
+ * @size:	size of the load option, on return size of the optional data
+ * Return:	status code
+ */
+efi_status_t efi_deserialize_load_option(struct efi_load_option_unpacked *lo, u8 *data,
+					 efi_uintn_t *size)
+{
+	efi_uintn_t len;
+
+	len = sizeof(u32);
+	if (*size < len + 2 * sizeof(u16))
+		return EFI_INVALID_PARAMETER;
+	lo->attributes = get_unaligned_le32(data);
+	data += len;
+	*size -= len;
+
+	len = sizeof(u16);
+	lo->file_path_length = get_unaligned_le16(data);
+	data += len;
+	*size -= len;
+
+	lo->label = (u16 *)data;
+	len = u16_strnlen(lo->label, *size / sizeof(u16) - 1);
+	if (lo->label[len])
+		return EFI_INVALID_PARAMETER;
+	len = (len + 1) * sizeof(u16);
+	if (*size < len)
+		return EFI_INVALID_PARAMETER;
+	data += len;
+	*size -= len;
+
+	len = lo->file_path_length;
+	if (*size < len)
+		return EFI_INVALID_PARAMETER;
+	lo->file_path = (struct efi_device_path *)data;
+	if (efi_dp_check_length(lo->file_path, len) < 0)
+		return EFI_INVALID_PARAMETER;
+	data += len;
+	*size -= len;
+
+	lo->optional_data = data;
+
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_serialize_load_option() - serialize load option
+ *
+ * Serialize efi_load_option structure into byte stream for BootXXXX.
+ *
+ * @data:	buffer for serialized data
+ * @lo:		load option
+ * Return:	size of allocated buffer
+ */
+size_t efi_serialize_load_option(struct efi_load_option_unpacked *lo, u8 **data)
+{
+	size_t label_len;
+	size_t size;
+	u8 *p;
+
+	label_len = u16_strsize(lo->label);
+
+	/* total size */
+	size = sizeof(lo->attributes);
+	size += sizeof(lo->file_path_length);
+	size += label_len;
+	size += lo->file_path_length;
+	if (lo->optional_data)
+		size += (utf8_utf16_strlen((const char *)lo->optional_data)
+					   + 1) * sizeof(u16);
+	p = malloc(size);
+	if (!p)
+		return 0;
+
+	/* copy data */
+	*data = p;
+	memcpy(p, &lo->attributes, sizeof(lo->attributes));
+	p += sizeof(lo->attributes);
+
+	memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length));
+	p += sizeof(lo->file_path_length);
+
+	memcpy(p, lo->label, label_len);
+	p += label_len;
+
+	memcpy(p, lo->file_path, lo->file_path_length);
+	p += lo->file_path_length;
+
+	if (lo->optional_data) {
+		utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data);
+		p += sizeof(u16); /* size of trailing \0 */
+	}
+	return size;
+}
diff --git a/include/efi/loader/option.h b/include/efi/loader/option.h
new file mode 100644
index 000000000000..9efc62c20e0b
--- /dev/null
+++ b/include/efi/loader/option.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+#ifndef __EFI_LOADER_OPTION_H__
+#define __EFI_LOADER_OPTION_H__
+
+#include <efi/types.h>
+
+/*
+ * See section 3.1.3 in the v2.7 UEFI spec for more details on
+ * the layout of EFI_LOAD_OPTION.  In short it is:
+ *
+ *    typedef struct _EFI_LOAD_OPTION {
+ *        UINT32 Attributes;
+ *        UINT16 FilePathListLength;
+ *        // CHAR16 Description[];   <-- variable length, NULL terminated
+ *        // EFI_DEVICE_PATH_PROTOCOL FilePathList[];
+ *						 <-- FilePathListLength bytes
+ *        // UINT8 OptionalData[];
+ *    } EFI_LOAD_OPTION;
+ */
+struct efi_load_option_unpacked {
+	u32 attributes;
+	u16 file_path_length;
+	u16 *label;
+	struct efi_device_path *file_path;
+	const u8 *optional_data;
+};
+
+efi_status_t efi_deserialize_load_option(struct efi_load_option_unpacked *lo,
+					 u8 *data, efi_uintn_t *size);
+size_t efi_serialize_load_option(struct efi_load_option_unpacked *lo,
+				 u8 **data);
+efi_status_t efi_set_load_options(efi_handle_t handle,
+				  efi_uintn_t load_options_size,
+				  void *load_options);
+
+#endif
-- 
2.47.3




More information about the barebox mailing list