uboot/lib/efi_selftest/efi_selftest_esrt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Test ESRT tables support
   4 *
   5 *  Copyright (C) 2021 Arm Ltd.
   6 */
   7#include <common.h>
   8#include <efi_loader.h>
   9#include <efi_selftest.h>
  10
  11// This value must not exceed 255.
  12// An FMP cannot contain more than 255 FW images.
  13#define TEST_ESRT_NUM_ENTRIES 255
  14
  15static
  16struct efi_firmware_image_descriptor static_img_info[TEST_ESRT_NUM_ENTRIES];
  17
  18static const struct efi_system_table *local_systable;
  19
  20static efi_handle_t fmp_handle;
  21
  22static const efi_guid_t efi_fmp_guid =
  23                EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
  24
  25static void efi_test_esrt_init_info(void)
  26{
  27        for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) {
  28                static_img_info[idx].image_index = idx;
  29
  30                // Note: the 16 byte value present in
  31                // static_img_info[idx].image_type_id is not strictly a GUID.
  32                // The value is used for the sake of code testing.
  33                static_img_info[idx].image_type_id.b[0] = idx;
  34
  35                static_img_info[idx].image_id = 0;
  36                static_img_info[idx].image_id_name = NULL;
  37                static_img_info[idx].version = 0;
  38                static_img_info[idx].version_name = NULL;
  39                static_img_info[idx].size = 0;
  40                static_img_info[idx].lowest_supported_image_version = 1;
  41                static_img_info[idx].last_attempt_version = 2;
  42                static_img_info[idx].last_attempt_status = 3;
  43                static_img_info[idx].hardware_instance = 1;
  44        }
  45}
  46
  47static efi_status_t
  48EFIAPI efi_test_fmp_get_image_info(struct efi_firmware_management_protocol *this,
  49                                   efi_uintn_t *image_info_size,
  50                                   struct efi_firmware_image_descriptor *image_info,
  51                                   u32 *descriptor_version,
  52                                   u8 *descriptor_count,
  53                                   efi_uintn_t *descriptor_size,
  54                                   u32 *package_version,
  55                                   u16 **package_version_name)
  56{
  57        efi_status_t ret = EFI_SUCCESS;
  58
  59        if (!image_info_size)
  60                return EFI_INVALID_PARAMETER;
  61
  62        if (descriptor_version)
  63                *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
  64        if (descriptor_count)
  65                *descriptor_count = TEST_ESRT_NUM_ENTRIES;
  66        if (descriptor_size)
  67                *descriptor_size = sizeof(*image_info);
  68        if (package_version)
  69                *package_version = 0xffffffff;
  70        if (package_version_name)
  71                *package_version_name = NULL;
  72
  73        if (*image_info_size < sizeof(*image_info)) {
  74                *image_info_size = *descriptor_size * *descriptor_count;
  75                return EFI_BUFFER_TOO_SMALL;
  76        }
  77
  78        for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
  79                image_info[idx] = static_img_info[idx];
  80
  81        return ret;
  82}
  83
  84static struct efi_firmware_management_protocol efi_test_fmp = {
  85        .get_image_info = efi_test_fmp_get_image_info,
  86        .get_image = NULL,
  87        .set_image = NULL,
  88        .check_image = NULL,
  89        .get_package_info = NULL,
  90        .set_package_info = NULL,
  91};
  92
  93static void *lib_test_get_esrt(void)
  94{
  95        for (int idx = 0; idx < local_systable->nr_tables; idx++)
  96                if (!guidcmp(&efi_esrt_guid, &local_systable->tables[idx].guid))
  97                        return local_systable->tables[idx].table;
  98
  99        return NULL;
 100}
 101
 102/**
 103 * lib_test_check_uuid_entry: Find an ESRT entry for which the fw_calss field matches
 104 * the image_type_id in the @img_info.
 105 * Ensure that all of the field in the ESRT entry have the same value as the corresponding
 106 * fields in the @img_info.
 107 *
 108 * @esrt: pointer to the ESRT
 109 * @img_info: an image_info_descriptor output by the FMP get_image_info
 110 *
 111 * @return: true if matching ESRT entry is found and if all the ESRT entry fields match the
 112 * corresponding @img_info fields.
 113 */
 114static bool lib_test_check_uuid_entry(struct efi_system_resource_table *esrt,
 115                                      struct efi_firmware_image_descriptor
 116                                      *img_info)
 117{
 118        const u32 filled_entries = esrt->fw_resource_count;
 119        struct efi_system_resource_entry *entry = esrt->entries;
 120
 121        for (u32 idx = 0; idx < filled_entries; idx++) {
 122                if (!guidcmp(&entry[idx].fw_class, &img_info->image_type_id)) {
 123                        if (entry[idx].fw_version != img_info->version) {
 124                                efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n",
 125                                             &img_info->image_type_id);
 126                                return false;
 127                        }
 128
 129                        if (entry[idx].lowest_supported_fw_version !=
 130                                img_info->lowest_supported_image_version) {
 131                                efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n",
 132                                             &img_info->image_type_id);
 133                                return false;
 134                        }
 135
 136                        if (entry[idx].last_attempt_version !=
 137                                img_info->last_attempt_version) {
 138                                efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n",
 139                                             &img_info->image_type_id);
 140                                return false;
 141                        }
 142
 143                        if (entry[idx].last_attempt_status !=
 144                                img_info->last_attempt_status) {
 145                                efi_st_error("ESRT field mismatch for entry with fw_class=%pUl\n",
 146                                             &img_info->image_type_id);
 147                                return false;
 148                        }
 149
 150                        /*
 151                         * The entry with fw_class = img_uuid matches with the
 152                         * remainder fmp input.
 153                         */
 154                        return true;
 155                }
 156        }
 157
 158        /* There exists no entry with fw_class equal to img_uuid in the ESRT. */
 159        efi_st_error("ESRT no entry with fw_class= %pUl\n", &img_info->image_type_id);
 160
 161        return false;
 162}
 163
 164/*
 165 * Setup unit test.
 166 *
 167 * Initialize the test FMP datastructure.
 168 *
 169 * @handle:     handle of the loaded image
 170 * @systable:   system table
 171 * @return:     EFI_ST_SUCCESS for success
 172 */
 173static int setup(const efi_handle_t handle,
 174                 const struct efi_system_table *systable)
 175{
 176        local_systable = systable;
 177
 178        efi_test_esrt_init_info();
 179
 180        return EFI_ST_SUCCESS;
 181}
 182
 183/*
 184 * Tear down unit test.
 185 *
 186 * Uninstall the test FMP.
 187 *
 188 * @return:     EFI_ST_SUCCESS for success
 189 */
 190static int teardown(void)
 191{
 192        efi_status_t ret = EFI_SUCCESS;
 193        struct efi_boot_services *bt;
 194
 195        bt = local_systable->boottime;
 196
 197        if (!bt) {
 198                efi_st_error("Cannot find boottime services structure\n");
 199                return EFI_ST_FAILURE;
 200        }
 201
 202        ret = bt->uninstall_multiple_protocol_interfaces
 203                (fmp_handle, &efi_fmp_guid,
 204                 &efi_test_fmp, NULL);
 205
 206        if (ret != EFI_SUCCESS) {
 207                efi_st_error("Failed to uninstall FMP\n");
 208                return EFI_ST_FAILURE;
 209        }
 210
 211        return EFI_ST_SUCCESS;
 212}
 213
 214/*
 215 * Perform the test
 216 *
 217 * The test consists of the following steps:
 218 *
 219 * 1) Obtain the ESRT
 220 * 2) Record the number of ESRT entries prior to test start
 221 * 3) Install the test FMP
 222 * 4) Re-obtain the ESRT (the ESRT pointer may have changed with the FMP install)
 223 * 5) verify that the ESRT entries have increased by the number of entries in the
 224 *     test FMP.
 225 * 6) Traverse all the elements used as the test FMP input and verify that each
 226 *     has a corresponding ESRT entry and that the fields are correctly set.
 227 *
 228 * The failure of any of the above steps results in a test failure.
 229 *
 230 */
 231static int execute(void)
 232{
 233        struct efi_system_resource_table *esrt;
 234        efi_status_t ret = EFI_SUCCESS;
 235        u32 base_entry_count;
 236        u32 entry_delta;
 237        struct efi_boot_services *bt;
 238
 239        bt = local_systable->boottime;
 240
 241        if (!bt) {
 242                efi_st_error("Cannot find boottime services structure\n");
 243                return EFI_ST_FAILURE;
 244        }
 245
 246        esrt = lib_test_get_esrt();
 247        if (!esrt) {
 248                efi_st_error("ESRT table not present\n");
 249                return EFI_ST_FAILURE;
 250        }
 251        base_entry_count = esrt->fw_resource_count;
 252
 253        ret = bt->install_multiple_protocol_interfaces(&fmp_handle,
 254                                                       &efi_fmp_guid,
 255                                                       &efi_test_fmp,
 256                                                       NULL);
 257
 258        if (ret != EFI_SUCCESS) {
 259                efi_st_error("Failed to install FMP\n");
 260                return EFI_ST_FAILURE;
 261        }
 262
 263        esrt = lib_test_get_esrt();
 264        if (!esrt) {
 265                efi_st_error("ESRT table not present\n");
 266                return EFI_ST_FAILURE;
 267        }
 268
 269        entry_delta = esrt->fw_resource_count - base_entry_count;
 270        if (entry_delta != TEST_ESRT_NUM_ENTRIES) {
 271                efi_st_error("ESRT mismatch in new entry count (%d), expected (%d).\n",
 272                             entry_delta, TEST_ESRT_NUM_ENTRIES);
 273                return EFI_ST_FAILURE;
 274        }
 275
 276        for (u32 idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++)
 277                if (!lib_test_check_uuid_entry(esrt, &static_img_info[idx])) {
 278                        efi_st_error("ESRT entry mismatch\n");
 279                        return EFI_ST_FAILURE;
 280                }
 281
 282        return EFI_ST_SUCCESS;
 283}
 284
 285EFI_UNIT_TEST(esrt) = {
 286        .name = "esrt",
 287        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 288        .setup = setup,
 289        .execute = execute,
 290        .teardown = teardown,
 291};
 292