efi_loader: Add helper functions for EFI

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 file paths stored in EFI variables.

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
This commit is contained in:
Ilias Apalodimas 2021-03-17 21:54:59 +02:00 committed by Heinrich Schuchardt
parent 76e8acce12
commit 37c3ca5c0b
5 changed files with 178 additions and 0 deletions

View File

@ -558,6 +558,11 @@ struct efi_simple_file_system_protocol *efi_simple_file_system(
/* open file from device-path: */
struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);
efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size);
/* get a device path from a Boot#### option */
struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid);
/**
* efi_size_in_pages() - convert size in bytes to size in pages
*
@ -723,6 +728,8 @@ efi_status_t EFIAPI efi_query_variable_info(
u64 *remaining_variable_storage_size,
u64 *maximum_variable_size);
void *efi_get_var(u16 *name, const efi_guid_t *vendor, efi_uintn_t *size);
/*
* 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:

View File

@ -23,6 +23,7 @@ endif
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o
obj-y += efi_boottime.o
obj-y += efi_helper.o
obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o
obj-y += efi_console.o

View File

@ -409,6 +409,45 @@ static efi_status_t efi_get_file_size(struct file_handle *fh,
return EFI_SUCCESS;
}
/**
* efi_file_size() - Get the size of a file using an EFI file handle
*
* @fh: EFI file handle
* @size: buffer to fill in the discovered size
*
* Return: size of the file
*/
efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size)
{
struct efi_file_info *info = NULL;
efi_uintn_t bs = 0;
efi_status_t ret;
*size = 0;
ret = EFI_CALL(fh->getinfo(fh, (efi_guid_t *)&efi_file_info_guid, &bs,
info));
if (ret != EFI_BUFFER_TOO_SMALL) {
ret = EFI_DEVICE_ERROR;
goto out;
}
info = malloc(bs);
if (!info) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
ret = EFI_CALL(fh->getinfo(fh, (efi_guid_t *)&efi_file_info_guid, &bs,
info));
if (ret != EFI_SUCCESS)
goto out;
*size = info->file_size;
out:
free(info);
return ret;
}
static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
void *buffer)
{

View File

@ -0,0 +1,98 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2020, Linaro Limited
*/
#define LOG_CATEGORY LOGC_EFI
#include <common.h>
#include <env.h>
#include <malloc.h>
#include <dm.h>
#include <fs.h>
#include <efi_load_initrd.h>
#include <efi_loader.h>
#include <efi_variable.h>
/**
* efi_create_current_boot_var() - Return Boot#### name were #### is replaced by
* the value of BootCurrent
*
* @var_name: variable name
* @var_name_size: size of var_name
*
* Return: Status code
*/
static efi_status_t efi_create_current_boot_var(u16 var_name[],
size_t var_name_size)
{
efi_uintn_t boot_current_size;
efi_status_t ret;
u16 boot_current;
u16 *pos;
boot_current_size = sizeof(boot_current);
ret = efi_get_variable_int(L"BootCurrent",
&efi_global_variable_guid, NULL,
&boot_current_size, &boot_current, NULL);
if (ret != EFI_SUCCESS)
goto out;
pos = efi_create_indexed_name(var_name, var_name_size, "Boot",
boot_current);
if (!pos) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
out:
return ret;
}
/**
* efi_get_dp_from_boot() - Retrieve and return a device path from an EFI
* Boot### variable.
* A boot option may contain an array of device paths.
* We use a VenMedia() with a specific GUID to identify
* the usage of the array members. This function is
* used to extract a specific device path
*
* @guid: vendor GUID of the VenMedia() device path node identifying the
* device path
*
* Return: device path or NULL. Caller must free the returned value
*/
struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid)
{
struct efi_device_path *file_path = NULL;
struct efi_device_path *tmp = NULL;
struct efi_load_option lo;
void *var_value = NULL;
efi_uintn_t size;
efi_status_t ret;
u16 var_name[16];
ret = efi_create_current_boot_var(var_name, sizeof(var_name));
if (ret != EFI_SUCCESS)
return NULL;
var_value = efi_get_var(var_name, &efi_global_variable_guid, &size);
if (!var_value)
return NULL;
ret = efi_deserialize_load_option(&lo, var_value, &size);
if (ret != EFI_SUCCESS)
goto out;
tmp = efi_dp_from_lo(&lo, &size, guid);
if (!tmp)
goto out;
/* efi_dp_dup will just return NULL if efi_dp_next is NULL */
file_path = efi_dp_dup(efi_dp_next(tmp));
out:
efi_free_pool(tmp);
free(var_value);
return file_path;
}

View File

@ -9,6 +9,7 @@
#include <common.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <stdlib.h>
enum efi_secure_mode {
EFI_MODE_SETUP,
@ -343,3 +344,35 @@ enum efi_auth_var_type efi_auth_var_get_type(u16 *name, const efi_guid_t *guid)
}
return EFI_AUTH_VAR_NONE;
}
/**
* efi_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 *efi_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);
if (!buf)
return NULL;
ret = efi_get_variable_int(name, vendor, NULL, size, buf, NULL);
}
if (ret != EFI_SUCCESS) {
free(buf);
*size = 0;
return NULL;
}
return buf;
}