blob: 922ff253c72cf71a266e281d03f2e0323514b094 [file] [log] [blame]
Jose Marinho5169ffc2021-03-11 13:18:52 +00001// 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 *
Heinrich Schuchardtfbe90212022-01-20 19:48:20 +0100111 * Return: true if matching ESRT entry is found and if all the ESRT entry fields match the
Jose Marinho5169ffc2021-03-11 13:18:52 +0000112 * 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) {
Heinrich Schuchardt513bb3d2022-01-16 15:49:17 +0100124 efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
Jose Marinho5169ffc2021-03-11 13:18:52 +0000125 &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) {
Heinrich Schuchardt513bb3d2022-01-16 15:49:17 +0100131 efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
Jose Marinho5169ffc2021-03-11 13:18:52 +0000132 &img_info->image_type_id);
133 return false;
134 }
135
136 if (entry[idx].last_attempt_version !=
137 img_info->last_attempt_version) {
Heinrich Schuchardt513bb3d2022-01-16 15:49:17 +0100138 efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
Jose Marinho5169ffc2021-03-11 13:18:52 +0000139 &img_info->image_type_id);
140 return false;
141 }
142
143 if (entry[idx].last_attempt_status !=
144 img_info->last_attempt_status) {
Heinrich Schuchardt513bb3d2022-01-16 15:49:17 +0100145 efi_st_error("ESRT field mismatch for entry with fw_class=%pU\n",
Jose Marinho5169ffc2021-03-11 13:18:52 +0000146 &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
Heinrich Schuchardtfbe90212022-01-20 19:48:20 +0100171 * Return: EFI_ST_SUCCESS for success
Jose Marinho5169ffc2021-03-11 13:18:52 +0000172 */
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 *
Heinrich Schuchardtfbe90212022-01-20 19:48:20 +0100188 * Return: EFI_ST_SUCCESS for success
Jose Marinho5169ffc2021-03-11 13:18:52 +0000189 */
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};