Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | // SPDX-License-Identifier: GPL-2.0-only /* * Test ESRT tables support * * Copyright (C) 2021 Arm Ltd. */ #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) * TEST_ESRT_NUM_ENTRIES) { *image_info_size = sizeof(*image_info) * TEST_ESRT_NUM_ENTRIES; return EFI_BUFFER_TOO_SMALL; } if (!image_info) return EFI_INVALID_PARAMETER; 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 * * Return: true if matching ESRT entry is found and if all the ESRT entry fields match the * 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) { efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n", &img_info->image_type_id); return false; } if (entry[idx].lowest_supported_fw_version != img_info->lowest_supported_image_version) { efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n", &img_info->image_type_id); return false; } if (entry[idx].last_attempt_version != img_info->last_attempt_version) { efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n", &img_info->image_type_id); return false; } if (entry[idx].last_attempt_status != img_info->last_attempt_status) { efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n", &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 * Return: EFI_ST_SUCCESS for success */ 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. * * Return: EFI_ST_SUCCESS for success */ 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, }; |