[PATCH 2/6] efi_loader: Introduce helper functions for EFI
Heinrich Schuchardt
xypron.glpk at gmx.de
Mon Dec 28 15:49:28 CET 2020
On 12/28/20 1:24 PM, Ilias Apalodimas wrote:
> A following patch introduces a different logic for loading initrd's
> based on the EFI_LOAD_FILE2_PROTOCOL.
> Since similar logic can be applied in the future for other system files
> (i.e DTBs). Let's add some helper functions which will retrieve and
> parse device paths via EFI variables.
>
> Signed-off-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
> ---
> include/efi_helper.h | 29 ++++++
> lib/efi_loader/efi_helper.c | 189 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 218 insertions(+)
> create mode 100644 include/efi_helper.h
> create mode 100644 lib/efi_loader/efi_helper.c
>
> diff --git a/include/efi_helper.h b/include/efi_helper.h
> new file mode 100644
> index 000000000000..d76e24e0f57d
> --- /dev/null
> +++ b/include/efi_helper.h
> @@ -0,0 +1,29 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (c) 2020, Linaro Limited
> + */
> +
> +#if !defined _EFI_HELPER_H_
> +#define _EFI_HELPER_H
> +
> +#include <efi.h>
> +#include <efi_api.h>
> +
> +/*
> + * @dev: device string i.e 'mmc'
> + * @part: partition string i.e '0:2'
> + * @filename: name of the file
> + */
> +struct load_file_info {
> + char dev[32];
> + char part[16];
> + char filename[256];
> +};
> +
> +loff_t get_file_size(const struct load_file_info *file_loc,
> + efi_status_t *status);
> +efi_status_t efi_get_fp_from_var(const u16 *name, u16 start,
> + struct load_file_info *loc);
> +void *get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size);
> +
> +#endif
> diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
> new file mode 100644
> index 000000000000..4cf1f8abed30
> --- /dev/null
> +++ b/lib/efi_loader/efi_helper.c
> @@ -0,0 +1,189 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (c) 2020, Linaro Limited
> + */
> +
> +#include <common.h>
> +#include <env.h>
> +#include <malloc.h>
> +#include <dm.h>
> +#include <fs.h>
> +#include <efi_helper.h>
> +#include <efi_loader.h>
> +#include <efi_variable.h>
> +
> +/**
> + * get_file_size() - retrieve the size of initramfs, set efi status on error
> + *
> + * @dev: device to read from, e.g. "mmc"
> + * @part: device partition, e.g. "0:1"
> + * @file: name of file
> + * @status: EFI exit code in case of failure
> + *
> + * Return: size of file
> + */
> +loff_t get_file_size(const struct load_file_info *info, efi_status_t *status)
> +{
> + loff_t sz = 0;
> + int ret;
> +
> + ret = fs_set_blk_dev(info->dev, info->part, FS_TYPE_ANY);
> + if (ret) {
> + *status = EFI_NO_MEDIA;
> + goto out;
> + }
> +
> + ret = fs_size(info->filename, &sz);
> + if (ret) {
> + sz = 0;
> + *status = EFI_NOT_FOUND;
> + goto out;
> + }
> +
> +out:
> + return sz;
> +}
> +
> +/*
> + * string_to_load_args() - Fill in a struct load_file_info with the file info
> + * parsed from an EFI variable
> + *
> + * @args: value of the EFI variable i.e "mmc 0 initrd"
> + * @info: struct to fill in with file specific info
> + *
> + * Return: Status code
> + */
> +static efi_status_t string_to_load_args(char *args, struct load_file_info *info)
> +{
> + efi_status_t status = EFI_SUCCESS;
> + char *p;
> +
> + /*
> + * expect a string with three space separated parts:
> + * - block device type, e.g. "mmc"
> + * - device and partition identifier, e.g. "0:1"
> + * - file path on the block device, e.g. "/boot/initrd.cpio.gz"
> + */
> + p = strsep(&args, " ");
> + if (!p) {
> + status = EFI_NO_MEDIA;
> + goto out;
> + }
> + strncpy(info->dev, p, sizeof(info->dev));
> +
> + p = strsep(&args, " ");
> + if (!p) {
> + status = EFI_NO_MEDIA;
> + goto out;
> + }
> + strncpy(info->part, p, sizeof(info->part));
> +
> + p = strsep(&args, " ");
> + if (!p) {
> + status = EFI_NOT_FOUND;
> + goto out;
> + }
> + strncpy(info->filename, p, sizeof(info->filename));
> +
> +out:
> + return status;
> +}
> +
> +/**
> + * get_var() - read value of an EFI variable
> + *
> + * @name: variable name
> + * @start: vendor GUID
> + * @size: size of allocated buffer
> + *
> + * Return: buffer with variable data or NULL
> + */
> +void *get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
> +{
> + efi_status_t ret;
> + void *buf = NULL;
> +
> + *size = 0;
> + ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
> + if (ret == EFI_BUFFER_TOO_SMALL) {
> + buf = malloc(*size);
> + ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
> + }
> +
> + if (ret != EFI_SUCCESS) {
> + free(buf);
> + *size = 0;
> + return NULL;
> + }
> +
> + return buf;
> +}
> +
> +/**
> + * efi_get_fp_from_var() - Retrieve a file path from an EFI variable
> + *
> + * @name: variable name
> + * @start: start replacing from
> + * @info: struct to fill in with file specific info
> + */
> +efi_status_t efi_get_fp_from_var(const u16 *name, u16 start,
> + struct load_file_info *info)
> +{
> + u16 hexmap[] = L"0123456789ABCDEF";
> + efi_uintn_t boot_order_size;
> + void *var_value = NULL;
> + u16 *name_dup = NULL;
> + efi_uintn_t size;
> + efi_status_t ret;
> + u16 boot_order;
> +
> + memset(info, 0, sizeof(*info));
> +
> + /* make sure we have enough space for replacements */
> + if (u16_strsize(name) < sizeof(*name) * start + u16_strsize(L"####")) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> + boot_order_size = sizeof(boot_order);
> + ret = efi_get_variable_int(L"BootCurrent",
> + &efi_global_variable_guid, NULL,
> + &boot_order_size, &boot_order, NULL);
> + if (ret != EFI_SUCCESS)
> + goto out;
> +
> + name_dup = u16_strdup(name);
> + if (!name_dup) {
> + ret = EFI_OUT_OF_RESOURCES;
> + goto out;
> + }
> + /* Match name variable to BootCurrent */
> + name_dup[start] = hexmap[(boot_order & 0xf000) >> 12];
> + name_dup[start + 1] = hexmap[(boot_order & 0x0f00) >> 8];
> + name_dup[start + 2] = hexmap[(boot_order & 0x00f0) >> 4];
> + name_dup[start + 3] = hexmap[(boot_order & 0x000f) >> 0];
Please, consider using efi_create_indexed_name().
Best regards
Heinrich
> +
> + var_value = get_var(name_dup, &efi_global_variable_guid, &size);
> + if (!var_value) {
> + ret = EFI_NOT_FOUND;
> + goto out;
> + }
> +
> + ret = string_to_load_args(var_value, info);
> + if (ret != EFI_SUCCESS)
> + goto out;
> +
> + if (fs_set_blk_dev(info->dev, info->part, FS_TYPE_ANY)) {
> + ret = EFI_NO_MEDIA;
> + goto out;
> + }
> +
> + if (!fs_exists(info->filename)) {
> + ret = EFI_NOT_FOUND;
> + goto out;
> + }
> +
> +out:
> + free(var_value);
> + free(name_dup);
> + return ret;
> +}
>
More information about the U-Boot
mailing list