2021-03-11 13:18:52 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
/*
|
|
|
|
* Test ESRT tables support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2021 Arm Ltd.
|
|
|
|
*/
|
|
|
|
#include <common.h>
|
|
|
|
#include <efi_loader.h>
|
|
|
|
#include <efi_selftest.h>
|
|
|
|
|
|
|
|
// This value must not exceed 255.
|
|
|
|
// An FMP cannot contain more than 255 FW images.
|
|
|
|
#define TEST_ESRT_NUM_ENTRIES 255
|
|
|
|
|
|
|
|
static
|
|
|
|
struct efi_firmware_image_descriptor static_img_info[TEST_ESRT_NUM_ENTRIES];
|
|
|
|
|
|
|
|
static const struct efi_system_table *local_systable;
|
|
|
|
|
|
|
|
static efi_handle_t fmp_handle;
|
|
|
|
|
|
|
|
static const efi_guid_t efi_fmp_guid =
|
|
|
|
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
|
|
|
|
|
|
|
|
static void efi_test_esrt_init_info(void)
|
|
|
|
{
|
|
|
|
for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) {
|
|
|
|
static_img_info[idx].image_index = idx;
|
|
|
|
|
|
|
|
// Note: the 16 byte value present in
|
|
|
|
// static_img_info[idx].image_type_id is not strictly a GUID.
|
|
|
|
// The value is used for the sake of code testing.
|
|
|
|
static_img_info[idx].image_type_id.b[0] = idx;
|
|
|
|
|
|
|
|
static_img_info[idx].image_id = 0;
|
|
|
|
static_img_info[idx].image_id_name = NULL;
|
|
|
|
static_img_info[idx].version = 0;
|
|
|
|
static_img_info[idx].version_name = NULL;
|
|
|
|
static_img_info[idx].size = 0;
|
|
|
|
static_img_info[idx].lowest_supported_image_version = 1;
|
|
|
|
static_img_info[idx].last_attempt_version = 2;
|
|
|
|
static_img_info[idx].last_attempt_status = 3;
|
|
|
|
static_img_info[idx].hardware_instance = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static efi_status_t
|
|
|
|
EFIAPI efi_test_fmp_get_image_info(struct efi_firmware_management_protocol *this,
|
|
|
|
efi_uintn_t *image_info_size,
|
|
|
|
struct efi_firmware_image_descriptor *image_info,
|
|
|
|
u32 *descriptor_version,
|
|
|
|
u8 *descriptor_count,
|
|
|
|
efi_uintn_t *descriptor_size,
|
|
|
|
u32 *package_version,
|
|
|
|
u16 **package_version_name)
|
|
|
|
{
|
|
|
|
efi_status_t ret = EFI_SUCCESS;
|
|
|
|
|
|
|
|
if (!image_info_size)
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
if (descriptor_version)
|
|
|
|
*descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
|
|
|
|
if (descriptor_count)
|
|
|
|
*descriptor_count = TEST_ESRT_NUM_ENTRIES;
|
|
|
|
if (descriptor_size)
|
|
|
|
*descriptor_size = sizeof(*image_info);
|
|
|
|
if (package_version)
|
|
|
|
*package_version = 0xffffffff;
|
|
|
|
if (package_version_name)
|
|
|
|
*package_version_name = NULL;
|
|
|
|
|
|
|
|
if (*image_info_size < sizeof(*image_info)) {
|
|
|
|
*image_info_size = *descriptor_size * *descriptor_count;
|
|
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
|
|
|
|
image_info[idx] = static_img_info[idx];
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct efi_firmware_management_protocol efi_test_fmp = {
|
|
|
|
.get_image_info = efi_test_fmp_get_image_info,
|
|
|
|
.get_image = NULL,
|
|
|
|
.set_image = NULL,
|
|
|
|
.check_image = NULL,
|
|
|
|
.get_package_info = NULL,
|
|
|
|
.set_package_info = NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *lib_test_get_esrt(void)
|
|
|
|
{
|
|
|
|
for (int idx = 0; idx < local_systable->nr_tables; idx++)
|
|
|
|
if (!guidcmp(&efi_esrt_guid, &local_systable->tables[idx].guid))
|
|
|
|
return local_systable->tables[idx].table;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* lib_test_check_uuid_entry: Find an ESRT entry for which the fw_calss field matches
|
|
|
|
* the image_type_id in the @img_info.
|
|
|
|
* Ensure that all of the field in the ESRT entry have the same value as the corresponding
|
|
|
|
* fields in the @img_info.
|
|
|
|
*
|
|
|
|
* @esrt: pointer to the ESRT
|
|
|
|
* @img_info: an image_info_descriptor output by the FMP get_image_info
|
|
|
|
*
|
2022-01-20 18:48:20 +00:00
|
|
|
* Return: true if matching ESRT entry is found and if all the ESRT entry fields match the
|
2021-03-11 13:18:52 +00:00
|
|
|
* corresponding @img_info fields.
|
|
|
|
*/
|
|
|
|
static bool lib_test_check_uuid_entry(struct efi_system_resource_table *esrt,
|
|
|
|
struct efi_firmware_image_descriptor
|
|
|
|
*img_info)
|
|
|
|
{
|
|
|
|
const u32 filled_entries = esrt->fw_resource_count;
|
|
|
|
struct efi_system_resource_entry *entry = esrt->entries;
|
|
|
|
|
|
|
|
for (u32 idx = 0; idx < filled_entries; idx++) {
|
|
|
|
if (!guidcmp(&entry[idx].fw_class, &img_info->image_type_id)) {
|
|
|
|
if (entry[idx].fw_version != img_info->version) {
|
2022-01-16 14:49:17 +00:00
|
|
|
efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
|
2021-03-11 13:18:52 +00:00
|
|
|
&img_info->image_type_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry[idx].lowest_supported_fw_version !=
|
|
|
|
img_info->lowest_supported_image_version) {
|
2022-01-16 14:49:17 +00:00
|
|
|
efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
|
2021-03-11 13:18:52 +00:00
|
|
|
&img_info->image_type_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry[idx].last_attempt_version !=
|
|
|
|
img_info->last_attempt_version) {
|
2022-01-16 14:49:17 +00:00
|
|
|
efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
|
2021-03-11 13:18:52 +00:00
|
|
|
&img_info->image_type_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry[idx].last_attempt_status !=
|
|
|
|
img_info->last_attempt_status) {
|
2022-01-16 14:49:17 +00:00
|
|
|
efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
|
2021-03-11 13:18:52 +00:00
|
|
|
&img_info->image_type_id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The entry with fw_class = img_uuid matches with the
|
|
|
|
* remainder fmp input.
|
|
|
|
*/
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* There exists no entry with fw_class equal to img_uuid in the ESRT. */
|
|
|
|
efi_st_error("ESRT no entry with fw_class= %pUl\n", &img_info->image_type_id);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup unit test.
|
|
|
|
*
|
|
|
|
* Initialize the test FMP datastructure.
|
|
|
|
*
|
|
|
|
* @handle: handle of the loaded image
|
|
|
|
* @systable: system table
|
2022-01-20 18:48:20 +00:00
|
|
|
* Return: EFI_ST_SUCCESS for success
|
2021-03-11 13:18:52 +00:00
|
|
|
*/
|
|
|
|
static int setup(const efi_handle_t handle,
|
|
|
|
const struct efi_system_table *systable)
|
|
|
|
{
|
|
|
|
local_systable = systable;
|
|
|
|
|
|
|
|
efi_test_esrt_init_info();
|
|
|
|
|
|
|
|
return EFI_ST_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tear down unit test.
|
|
|
|
*
|
|
|
|
* Uninstall the test FMP.
|
|
|
|
*
|
2022-01-20 18:48:20 +00:00
|
|
|
* Return: EFI_ST_SUCCESS for success
|
2021-03-11 13:18:52 +00:00
|
|
|
*/
|
|
|
|
static int teardown(void)
|
|
|
|
{
|
|
|
|
efi_status_t ret = EFI_SUCCESS;
|
|
|
|
struct efi_boot_services *bt;
|
|
|
|
|
|
|
|
bt = local_systable->boottime;
|
|
|
|
|
|
|
|
if (!bt) {
|
|
|
|
efi_st_error("Cannot find boottime services structure\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = bt->uninstall_multiple_protocol_interfaces
|
|
|
|
(fmp_handle, &efi_fmp_guid,
|
|
|
|
&efi_test_fmp, NULL);
|
|
|
|
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("Failed to uninstall FMP\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_ST_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform the test
|
|
|
|
*
|
|
|
|
* The test consists of the following steps:
|
|
|
|
*
|
|
|
|
* 1) Obtain the ESRT
|
|
|
|
* 2) Record the number of ESRT entries prior to test start
|
|
|
|
* 3) Install the test FMP
|
|
|
|
* 4) Re-obtain the ESRT (the ESRT pointer may have changed with the FMP install)
|
|
|
|
* 5) verify that the ESRT entries have increased by the number of entries in the
|
|
|
|
* test FMP.
|
|
|
|
* 6) Traverse all the elements used as the test FMP input and verify that each
|
|
|
|
* has a corresponding ESRT entry and that the fields are correctly set.
|
|
|
|
*
|
|
|
|
* The failure of any of the above steps results in a test failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static int execute(void)
|
|
|
|
{
|
|
|
|
struct efi_system_resource_table *esrt;
|
|
|
|
efi_status_t ret = EFI_SUCCESS;
|
|
|
|
u32 base_entry_count;
|
|
|
|
u32 entry_delta;
|
|
|
|
struct efi_boot_services *bt;
|
|
|
|
|
|
|
|
bt = local_systable->boottime;
|
|
|
|
|
|
|
|
if (!bt) {
|
|
|
|
efi_st_error("Cannot find boottime services structure\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
esrt = lib_test_get_esrt();
|
|
|
|
if (!esrt) {
|
|
|
|
efi_st_error("ESRT table not present\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
base_entry_count = esrt->fw_resource_count;
|
|
|
|
|
|
|
|
ret = bt->install_multiple_protocol_interfaces(&fmp_handle,
|
|
|
|
&efi_fmp_guid,
|
|
|
|
&efi_test_fmp,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
|
efi_st_error("Failed to install FMP\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
esrt = lib_test_get_esrt();
|
|
|
|
if (!esrt) {
|
|
|
|
efi_st_error("ESRT table not present\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry_delta = esrt->fw_resource_count - base_entry_count;
|
|
|
|
if (entry_delta != TEST_ESRT_NUM_ENTRIES) {
|
|
|
|
efi_st_error("ESRT mismatch in new entry count (%d), expected (%d).\n",
|
|
|
|
entry_delta, TEST_ESRT_NUM_ENTRIES);
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (u32 idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
|
|
|
|
if (!lib_test_check_uuid_entry(esrt, &static_img_info[idx])) {
|
|
|
|
efi_st_error("ESRT entry mismatch\n");
|
|
|
|
return EFI_ST_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_ST_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_UNIT_TEST(esrt) = {
|
|
|
|
.name = "esrt",
|
|
|
|
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
|
|
|
|
.setup = setup,
|
|
|
|
.execute = execute,
|
|
|
|
.teardown = teardown,
|
|
|
|
};
|