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