Import the load option utility functions from U-Boot, so barebox can pass along the kernel command line.
Signed-off-by: Ahmad Fatoum <[email protected]> --- 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
