Commit 49f8849d authored by Tom Rini's avatar Tom Rini
Browse files

Merge tag 'signed-efi-2018.05' of git://github.com/agraf/u-boot

Patch queue for efi - 2018-04-23

Some last minute fixes for 2018.05. Most of them are minor fixes. On
top we have some functional improvements for the device path logic
which should also help us be more compatible.
parents ec360e64 e83222bf
......@@ -324,6 +324,8 @@ This driver is only available if U-Boot is configured with
* persistence
* runtime support
* support bootefi booting ARMv7 in non-secure mode (CONFIG_ARMV7_NONSEC=y)
## Links
* [1](http://uefi.org/specifications)
......
......@@ -343,6 +343,7 @@ struct efi_loaded_image {
0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
#define DEVICE_PATH_TYPE_END 0x7f
# define DEVICE_PATH_SUB_TYPE_INSTANCE_END 0x01
# define DEVICE_PATH_SUB_TYPE_END 0xff
struct efi_device_path {
......
......@@ -324,13 +324,28 @@ int efi_dp_match(const struct efi_device_path *a,
const struct efi_device_path *b);
struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
struct efi_device_path **rem);
unsigned efi_dp_size(const struct efi_device_path *dp);
/* get size of the first device path instance excluding end node */
efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp);
/* size of multi-instance device path excluding end node */
efi_uintn_t efi_dp_size(const struct efi_device_path *dp);
struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp);
struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
const struct efi_device_path *dp2);
struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
const struct efi_device_path *node);
/* Create a device path node of given type, sub-type, length */
struct efi_device_path *efi_dp_create_device_node(const u8 type,
const u8 sub_type,
const u16 length);
/* Append device path instance */
struct efi_device_path *efi_dp_append_instance(
const struct efi_device_path *dp,
const struct efi_device_path *dpi);
/* Get next device path instance */
struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
efi_uintn_t *size);
/* Check if a device path contains muliple instances */
bool efi_dp_is_multi_instance(const struct efi_device_path *dp);
struct efi_device_path *efi_dp_from_dev(struct udevice *dev);
struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part);
......
......@@ -114,6 +114,7 @@ u16 efi_st_get_key(void);
* @setup: set up the unit test
* @teardown: tear down the unit test
* @execute: execute the unit test
* @setup_ok: setup was successful (set at runtime)
* @on_request: test is only executed on request
*/
struct efi_unit_test {
......@@ -123,6 +124,7 @@ struct efi_unit_test {
const struct efi_system_table *systable);
int (*execute)(void);
int (*teardown)(void);
int setup_ok;
bool on_request;
};
......
......@@ -46,7 +46,7 @@ enum log_category_t {
LOGC_CORE,
LOGC_DM, /* Core driver-model */
LOGC_DT, /* Device-tree */
LOGL_EFI, /* EFI implementation */
LOGC_EFI, /* EFI implementation */
LOGC_COUNT,
LOGC_END,
......
config EFI_LOADER
bool "Support running EFI Applications in U-Boot"
depends on (ARM || X86) && OF_LIBFDT
# We do not support bootefi booting ARMv7 in non-secure mode
depends on !ARMV7_NONSEC
# We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB
depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT
# We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB
......
......@@ -2219,7 +2219,7 @@ static efi_status_t EFIAPI efi_locate_device_path(
}
/* Find end of device path */
len = efi_dp_size(*device_path);
len = efi_dp_instance_size(*device_path);
/* Get all handles implementing the protocol */
ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
......@@ -2234,7 +2234,7 @@ static efi_status_t EFIAPI efi_locate_device_path(
if (ret != EFI_SUCCESS)
continue;
dp = (struct efi_device_path *)handler->protocol_interface;
len_dp = efi_dp_size(dp);
len_dp = efi_dp_instance_size(dp);
/*
* This handle can only be a better fit
* if its device path length is longer than the best fit and
......
......@@ -149,7 +149,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
struct efi_device_path **rem)
{
struct efi_object *efiobj;
unsigned int dp_size = efi_dp_size(dp);
efi_uintn_t dp_size = efi_dp_instance_size(dp);
list_for_each_entry(efiobj, &efi_obj_list, link) {
struct efi_handler *handler;
......@@ -170,11 +170,12 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
* the caller.
*/
*rem = ((void *)dp) +
efi_dp_size(obj_dp);
efi_dp_instance_size(obj_dp);
return efiobj;
} else {
/* Only return on exact matches */
if (efi_dp_size(obj_dp) == dp_size)
if (efi_dp_instance_size(obj_dp) ==
dp_size)
return efiobj;
}
}
......@@ -229,11 +230,13 @@ const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
return ret;
}
/* return size not including End node: */
unsigned efi_dp_size(const struct efi_device_path *dp)
/* get size of the first device path instance excluding end node */
efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
{
unsigned sz = 0;
efi_uintn_t sz = 0;
if (!dp || dp->type == DEVICE_PATH_TYPE_END)
return 0;
while (dp) {
sz += dp->length;
dp = efi_dp_next(dp);
......@@ -242,10 +245,25 @@ unsigned efi_dp_size(const struct efi_device_path *dp)
return sz;
}
/* get size of multi-instance device path excluding end node */
efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
{
const struct efi_device_path *p = dp;
if (!p)
return 0;
while (p->type != DEVICE_PATH_TYPE_END ||
p->sub_type != DEVICE_PATH_SUB_TYPE_END)
p = (void *)p + p->length;
return (void *)p - (void *)dp;
}
/* copy multi-instance device path */
struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
{
struct efi_device_path *ndp;
unsigned sz = efi_dp_size(dp) + sizeof(END);
size_t sz = efi_dp_size(dp) + sizeof(END);
if (!dp)
return NULL;
......@@ -263,7 +281,10 @@ struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
{
struct efi_device_path *ret;
if (!dp1) {
if (!dp1 && !dp2) {
/* return an end node */
ret = efi_dp_dup(&END);
} else if (!dp1) {
ret = efi_dp_dup(dp2);
} else if (!dp2) {
ret = efi_dp_dup(dp1);
......@@ -275,8 +296,8 @@ struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
if (!p)
return NULL;
memcpy(p, dp1, sz1);
memcpy(p + sz1, dp2, sz2);
memcpy(p + sz1 + sz2, &END, sizeof(END));
/* the end node of the second device path has to be retained */
memcpy(p + sz1, dp2, sz2 + sizeof(END));
ret = p;
}
......@@ -293,7 +314,7 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
} else if (!node) {
ret = efi_dp_dup(dp);
} else if (!dp) {
unsigned sz = node->length;
size_t sz = node->length;
void *p = dp_alloc(sz + sizeof(END));
if (!p)
return NULL;
......@@ -302,7 +323,7 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
ret = p;
} else {
/* both dp and node are non-null */
unsigned sz = efi_dp_size(dp);
size_t sz = efi_dp_size(dp);
void *p = dp_alloc(sz + node->length + sizeof(END));
if (!p)
return NULL;
......@@ -315,6 +336,85 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
return ret;
}
struct efi_device_path *efi_dp_create_device_node(const u8 type,
const u8 sub_type,
const u16 length)
{
struct efi_device_path *ret;
ret = dp_alloc(length);
if (!ret)
return ret;
ret->type = type;
ret->sub_type = sub_type;
ret->length = length;
return ret;
}
struct efi_device_path *efi_dp_append_instance(
const struct efi_device_path *dp,
const struct efi_device_path *dpi)
{
size_t sz, szi;
struct efi_device_path *p, *ret;
if (!dpi)
return NULL;
if (!dp)
return efi_dp_dup(dpi);
sz = efi_dp_size(dp);
szi = efi_dp_instance_size(dpi);
p = dp_alloc(sz + szi + 2 * sizeof(END));
if (!p)
return NULL;
ret = p;
memcpy(p, dp, sz + sizeof(END));
p = (void *)p + sz;
p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
p = (void *)p + sizeof(END);
memcpy(p, dpi, szi);
p = (void *)p + szi;
memcpy(p, &END, sizeof(END));
return ret;
}
struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
efi_uintn_t *size)
{
size_t sz;
struct efi_device_path *p;
if (size)
*size = 0;
if (!dp || !*dp)
return NULL;
p = *dp;
sz = efi_dp_instance_size(*dp);
p = dp_alloc(sz + sizeof(END));
if (!p)
return NULL;
memcpy(p, *dp, sz + sizeof(END));
*dp = (void *)*dp + sz;
if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
*dp = (void *)*dp + sizeof(END);
else
*dp = NULL;
if (size)
*size = sz + sizeof(END);
return p;
}
bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
{
const struct efi_device_path *p = dp;
if (!p)
return false;
while (p->type != DEVICE_PATH_TYPE_END)
p = (void *)p + p->length;
return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
}
#ifdef CONFIG_DM
/* size of device-path not including END node for device and all parents
* up to the root device.
......
......@@ -12,69 +12,180 @@
const efi_guid_t efi_guid_device_path_utilities_protocol =
EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
/*
* Get size of a device path.
*
* This function implements the GetDevicePathSize service of the device path
* utilities protocol. The device path length includes the end of path tag
* which may be an instance end.
*
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @device_path device path
* @return size in bytes
*/
static efi_uintn_t EFIAPI get_device_path_size(
const struct efi_device_path *device_path)
{
efi_uintn_t sz = 0;
EFI_ENTRY("%p", device_path);
EFI_ENTRY("%pD", device_path);
/* size includes the END node: */
if (device_path)
sz = efi_dp_size(device_path) + sizeof(struct efi_device_path);
return EFI_EXIT(sz);
}
/*
* Duplicate a device path.
*
* This function implements the DuplicateDevicePath service of the device path
* utilities protocol.
*
* The UEFI spec does not indicate what happens to the end tag. We follow the
* EDK2 logic: In case the device path ends with an end of instance tag, the
* copy will also end with an end of instance tag.
*
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @device_path device path
* @return copy of the device path
*/
static struct efi_device_path * EFIAPI duplicate_device_path(
const struct efi_device_path *device_path)
{
EFI_ENTRY("%p", device_path);
EFI_ENTRY("%pD", device_path);
return EFI_EXIT(efi_dp_dup(device_path));
}
/*
* Append device path.
*
* This function implements the AppendDevicePath service of the device path
* utilities protocol.
*
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @src1 1st device path
* @src2 2nd device path
* @return concatenated device path
*/
static struct efi_device_path * EFIAPI append_device_path(
const struct efi_device_path *src1,
const struct efi_device_path *src2)
{
EFI_ENTRY("%p, %p", src1, src2);
EFI_ENTRY("%pD, %pD", src1, src2);
return EFI_EXIT(efi_dp_append(src1, src2));
}
/*
* Append device path node.
*
* This function implements the AppendDeviceNode service of the device path
* utilities protocol.
*
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @device_path device path
* @device_node device node
* @return concatenated device path
*/
static struct efi_device_path * EFIAPI append_device_node(
const struct efi_device_path *device_path,
const struct efi_device_path *device_node)
{
EFI_ENTRY("%p, %p", device_path, device_node);
EFI_ENTRY("%pD, %p", device_path, device_node);
return EFI_EXIT(efi_dp_append_node(device_path, device_node));
}
/*
* Append device path instance.
*
* This function implements the AppendDevicePathInstance service of the device
* path utilities protocol.
*
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @device_path 1st device path
* @device_path_instance 2nd device path
* @return concatenated device path
*/
static struct efi_device_path * EFIAPI append_device_path_instance(
const struct efi_device_path *device_path,
const struct efi_device_path *device_path_instance)
{
EFI_ENTRY("%p, %p", device_path, device_path_instance);
return EFI_EXIT(NULL);
EFI_ENTRY("%pD, %pD", device_path, device_path_instance);
return EFI_EXIT(efi_dp_append_instance(device_path,
device_path_instance));
}
/*
* Get next device path instance.
*
* This function implements the GetNextDevicePathInstance service of the device
* path utilities protocol.
*
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @device_path_instance next device path instance
* @device_path_instance_size size of the device path instance
* @return concatenated device path
*/
static struct efi_device_path * EFIAPI get_next_device_path_instance(
struct efi_device_path **device_path_instance,
efi_uintn_t *device_path_instance_size)
{
EFI_ENTRY("%p, %p", device_path_instance, device_path_instance_size);
return EFI_EXIT(NULL);
EFI_ENTRY("%pD, %p", device_path_instance, device_path_instance_size);
return EFI_EXIT(efi_dp_get_next_instance(device_path_instance,
device_path_instance_size));
}
/*
* Check if a device path contains more than one instance.
*
* This function implements the AppendDeviceNode service of the device path
* utilities protocol.
*
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @device_path device path
* @device_node device node
* @return concatenated device path
*/
static bool EFIAPI is_device_path_multi_instance(
const struct efi_device_path *device_path)
{
EFI_ENTRY("%p", device_path);
return EFI_EXIT(false);
EFI_ENTRY("%pD", device_path);
return EFI_EXIT(efi_dp_is_multi_instance(device_path));
}
/*
* Create device node.
*
* This function implements the CreateDeviceNode service of the device path
* utilities protocol.
*
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @node_type node type
* @node_sub_type node sub type
* @node_length node length
* @return device path node
*/
static struct efi_device_path * EFIAPI create_device_node(
uint8_t node_type, uint8_t node_sub_type, uint16_t node_length)
{
EFI_ENTRY("%u, %u, %u", node_type, node_sub_type, node_length);
return EFI_EXIT(NULL);
return EFI_EXIT(efi_dp_create_device_node(node_type, node_sub_type,
node_length));
}
const struct efi_device_path_utilities_protocol efi_device_path_utilities = {
......
......@@ -18,6 +18,7 @@ efi_selftest_bitblt.o \
efi_selftest_controllers.o \
efi_selftest_console.o \
efi_selftest_devicepath.o \
efi_selftest_devicepath_util.o \
efi_selftest_events.o \
efi_selftest_event_groups.o \
efi_selftest_exitbootservices.o \
......
......@@ -77,20 +77,20 @@ void efi_st_exit_boot_services(void)
*/
static int setup(struct efi_unit_test *test, unsigned int *failures)
{
int ret;
if (!test->setup)
if (!test->setup) {
test->setup_ok = EFI_ST_SUCCESS;
return EFI_ST_SUCCESS;
}
efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name);
ret = test->setup(handle, systable);
if (ret != EFI_ST_SUCCESS) {
test->setup_ok = test->setup(handle, systable);
if (test->setup_ok != EFI_ST_SUCCESS) {
efi_st_error("Setting up '%s' failed\n", test->name);
++*failures;
} else {
efi_st_printc(EFI_LIGHTGREEN,
"Setting up '%s' succeeded\n", test->name);
}
return ret;
return test->setup_ok;
}
/*
......@@ -200,7 +200,7 @@ void efi_st_do_tests(const u16 *testname, unsigned int phase,
continue;
if (steps & EFI_ST_SETUP)
setup(test, failures);
if (steps & EFI_ST_EXECUTE)
if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS)
execute(test, failures);
if (steps & EFI_ST_TEARDOWN)
teardown(test, failures);
......
......@@ -52,7 +52,7 @@ struct efi_device_path_to_text_protocol *device_path_to_text;
* Setup unit test.
*
* Create three handles. Install a new protocol on two of them and
* provice device paths.
* provide device paths.
*
* handle1
* guid interface
......
/*
* efi_selftest_devicepath_util
*
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* This unit test checks the device path utilities protocol.
*/
#include <efi_selftest.h>
static struct efi_boot_services *boottime;
static efi_guid_t guid_device_path_utilities_protocol =
EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
struct efi_device_path_utilities_protocol *dpu;
/*
* Setup unit test.
*
* Locate the device path utilities protocol.
*
* @handle: handle of the loaded image
* @systable: system table
*/
static int setup(const efi_handle_t img_handle,
const struct efi_system_table *systable)
{
int ret;
boottime = systable->boottime;
ret = boottime->locate_protocol(&guid_device_path_utilities_protocol,
NULL, (void **)&dpu);
if (ret != EFI_SUCCESS) {
dpu = NULL;
efi_st_error(
"Device path to text protocol is not available.\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
/*
* Create a device path consisting of a single media device node followed by an
* end node.
*
* @length: length of the media device node
* @dp: device path
* @return: status code
*/
static int create_single_node_device_path(unsigned int length,
struct efi_device_path **dp)
{
struct efi_device_path *node;
efi_uintn_t len;
int ret;
node = dpu->create_device_node(DEVICE_PATH_TYPE_MEDIA_DEVICE,
DEVICE_PATH_SUB_TYPE_FILE_PATH, length);
if (!node) {
efi_st_error("CreateDeviceNode failed\n");
return EFI_ST_FAILURE;
}
*dp = dpu->append_device_node(NULL, node);
if (!*dp) {
efi_st_error("AppendDeviceNode failed\n");
return EFI_ST_FAILURE;
}
ret = boottime->free_pool(node);
if (ret != EFI_ST_SUCCESS) {
efi_st_error("FreePool failed\n");
return EFI_ST_FAILURE;