[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