1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  EFI application ESRT tables support
4  *
5  *  Copyright (C) 2021 Arm Ltd.
6  */
7 
8 #include <common.h>
9 #include <efi_loader.h>
10 #include <log.h>
11 #include <efi_api.h>
12 #include <malloc.h>
13 
14 const efi_guid_t efi_esrt_guid = EFI_SYSTEM_RESOURCE_TABLE_GUID;
15 
16 static struct efi_system_resource_table *esrt;
17 
18 #define EFI_ESRT_VERSION 1
19 
20 /**
21  * efi_esrt_image_info_to_entry() - copy the information present in a fw image
22  * descriptor to a ESRT entry.
23  * The function ensures the ESRT entry matches the image_type_id in @img_info.
24  * In case of a mismatch we leave the entry unchanged.
25  *
26  * @img_info:     the source image info descriptor
27  * @entry:        pointer to the ESRT entry to be filled
28  * @desc_version: the version of the elements in img_info
29  * @image_type:   the image type value to be set in the ESRT entry
30  * @flags:        the capsule flags value to be set in the ESRT entry
31  *
32  * Return:
33  * - EFI_SUCCESS if the entry is correctly updated
34  * - EFI_INVALID_PARAMETER if entry does not match image_type_id in @img_info.
35  */
36 static efi_status_t
efi_esrt_image_info_to_entry(struct efi_firmware_image_descriptor * img_info,struct efi_system_resource_entry * entry,u32 desc_version,u32 image_type,u32 flags)37 efi_esrt_image_info_to_entry(struct efi_firmware_image_descriptor *img_info,
38 			     struct efi_system_resource_entry *entry,
39 			     u32 desc_version, u32 image_type, u32 flags)
40 {
41 	if (guidcmp(&entry->fw_class, &img_info->image_type_id)) {
42 		EFI_PRINT("ESRT entry %pUL mismatches img_type_id %pUL\n",
43 			  &entry->fw_class, &img_info->image_type_id);
44 		return EFI_INVALID_PARAMETER;
45 	}
46 
47 	entry->fw_version = img_info->version;
48 
49 	entry->fw_type = image_type;
50 	entry->capsule_flags = flags;
51 
52 	/*
53 	 * The field lowest_supported_image_version is only present
54 	 * on image info structure of version 2 or greater.
55 	 * See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI.
56 	 */
57 	if (desc_version >= 2)
58 		entry->lowest_supported_fw_version =
59 			img_info->lowest_supported_image_version;
60 	else
61 		entry->lowest_supported_fw_version = 0;
62 
63 	/*
64 	 * The fields last_attempt_version and last_attempt_status
65 	 * are only present on image info structure of version 3 or
66 	 * greater.
67 	 * See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI.
68 	 */
69 	if (desc_version >= 3) {
70 		entry->last_attempt_version =
71 			img_info->last_attempt_version;
72 
73 		entry->last_attempt_status =
74 			img_info->last_attempt_status;
75 	} else {
76 		entry->last_attempt_version = 0;
77 		entry->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
78 	}
79 
80 	return EFI_SUCCESS;
81 }
82 
83 /**
84  * efi_esrt_entries_to_size() - Obtain the bytes used by an ESRT
85  * datastructure with @num_entries.
86  *
87  * @num_entries: the number of entries in the ESRT.
88  *
89  * Return: the number of bytes an ESRT with @num_entries occupies in memory.
90  */
91 static
efi_esrt_entries_to_size(u32 num_entries)92 inline u32 efi_esrt_entries_to_size(u32 num_entries)
93 {
94 	u32 esrt_size = sizeof(struct efi_system_resource_table) +
95 		num_entries * sizeof(struct efi_system_resource_entry);
96 
97 	return esrt_size;
98 }
99 
100 /**
101  * efi_esrt_allocate_install() - Allocates @num_entries for the ESRT and
102  * performs basic ESRT initialization.
103  *
104  * @num_entries: the number of entries that the ESRT will hold.
105  *
106  * Return:
107  * - pointer to the ESRT if successful.
108  * - NULL otherwise.
109  */
110 static
efi_esrt_allocate_install(u32 num_entries)111 efi_status_t efi_esrt_allocate_install(u32 num_entries)
112 {
113 	efi_status_t ret;
114 	struct efi_system_resource_table *new_esrt;
115 	u32 size = efi_esrt_entries_to_size(num_entries);
116 	efi_guid_t esrt_guid = efi_esrt_guid;
117 
118 	/* Reserve num_pages for ESRT */
119 	ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, size,
120 				(void **)&new_esrt);
121 
122 	if (ret != EFI_SUCCESS) {
123 		EFI_PRINT("ESRT cannot allocate memory for %u entries (%u bytes)\n",
124 			  num_entries, size);
125 
126 		return ret;
127 	}
128 
129 	new_esrt->fw_resource_count_max = num_entries;
130 	new_esrt->fw_resource_count = 0;
131 	new_esrt->fw_resource_version = EFI_ESRT_VERSION;
132 
133 	/* Install the ESRT in the system configuration table. */
134 	ret = efi_install_configuration_table(&esrt_guid, (void *)new_esrt);
135 	if (ret != EFI_SUCCESS) {
136 		EFI_PRINT("ESRT failed to install the ESRT in the system table\n");
137 		return ret;
138 	}
139 
140 	/* If there was a previous ESRT, deallocate its memory now. */
141 	if (esrt)
142 		ret = efi_free_pool(esrt);
143 
144 	esrt = new_esrt;
145 
146 	return EFI_SUCCESS;
147 }
148 
149 /**
150  * esrt_find_entry() - Obtain the ESRT entry for the image with GUID
151  * @img_fw_class.
152  *
153  * If the img_fw_class is not yet present in the ESRT, this function
154  * reserves the tail element of the current ESRT as the entry for that fw_class.
155  * The number of elements in the ESRT is updated in that case.
156  *
157  * @img_fw_class: the GUID of the FW image which ESRT entry we want to obtain.
158  *
159  * Return:
160  *  - A pointer to the ESRT entry for the image with GUID img_fw_class,
161  *  - NULL if:
162  *   - there is no more space in the ESRT,
163  *   - ESRT is not initialized,
164  */
165 static
esrt_find_entry(efi_guid_t * img_fw_class)166 struct efi_system_resource_entry *esrt_find_entry(efi_guid_t *img_fw_class)
167 {
168 	u32 filled_entries;
169 	u32 max_entries;
170 	struct efi_system_resource_entry *entry;
171 
172 	if (!esrt) {
173 		EFI_PRINT("ESRT access before initialized\n");
174 		return NULL;
175 	}
176 
177 	filled_entries = esrt->fw_resource_count;
178 	entry = esrt->entries;
179 
180 	/* Check if the image with img_fw_class is already in the ESRT. */
181 	for (u32 idx = 0; idx < filled_entries; idx++) {
182 		if (!guidcmp(&entry[idx].fw_class, img_fw_class)) {
183 			EFI_PRINT("ESRT found entry for image %pUl at index %u\n",
184 				  img_fw_class, idx);
185 			return &entry[idx];
186 		}
187 	}
188 
189 	max_entries = esrt->fw_resource_count_max;
190 	/*
191 	 * Since the image with img_fw_class is not present in the ESRT, check
192 	 * if ESRT is full before appending the new entry to it.
193 	 */
194 	if (filled_entries == max_entries) {
195 		EFI_PRINT("ESRT full, this should not happen\n");
196 		return NULL;
197 	}
198 
199 	/*
200 	 * This is a new entry for a fw image, increment the element
201 	 * number in the table and set the fw_class field.
202 	 */
203 	esrt->fw_resource_count++;
204 	entry[filled_entries].fw_class = *img_fw_class;
205 	EFI_PRINT("ESRT allocated new entry for image %pUl at index %u\n",
206 		  img_fw_class, filled_entries);
207 
208 	return &entry[filled_entries];
209 }
210 
211 /**
212  * efi_esrt_add_from_fmp() - Populates a sequence of ESRT entries from the FW
213  * images in the FMP.
214  *
215  * @fmp: the FMP instance from which FW images are added to the ESRT
216  *
217  * Return:
218  * - EFI_SUCCESS if all the FW images in the FMP are added to the ESRT
219  * - Error status otherwise
220  */
221 static
efi_esrt_add_from_fmp(struct efi_firmware_management_protocol * fmp)222 efi_status_t efi_esrt_add_from_fmp(struct efi_firmware_management_protocol *fmp)
223 {
224 	struct efi_system_resource_entry *entry = NULL;
225 	size_t info_size = 0;
226 	struct efi_firmware_image_descriptor *img_info = NULL;
227 	u32 desc_version;
228 	u8 desc_count;
229 	size_t desc_size;
230 	u32 package_version;
231 	u16 *package_version_name;
232 	efi_status_t ret = EFI_SUCCESS;
233 
234 	/*
235 	 * TODO: set the field image_type depending on the FW image type
236 	 * defined in a platform basis.
237 	 */
238 	u32 image_type = ESRT_FW_TYPE_UNKNOWN;
239 
240 	/* TODO: set the capsule flags as a function of the FW image type. */
241 	u32 flags = 0;
242 
243 	ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
244 					   &desc_version, &desc_count,
245 					   &desc_size, NULL, NULL));
246 
247 	if (ret != EFI_BUFFER_TOO_SMALL) {
248 		/*
249 		 * An input of info_size=0 should always lead
250 		 * fmp->get_image_info to return BUFFER_TO_SMALL.
251 		 */
252 		EFI_PRINT("Erroneous FMP implementation\n");
253 		return EFI_INVALID_PARAMETER;
254 	}
255 
256 	ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
257 				(void **)&img_info);
258 	if (ret != EFI_SUCCESS) {
259 		EFI_PRINT("ESRT failed to allocate memory for image info.\n");
260 		return ret;
261 	}
262 
263 	ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
264 					   &desc_version, &desc_count,
265 					   &desc_size, &package_version,
266 					   &package_version_name));
267 	if (ret != EFI_SUCCESS) {
268 		EFI_PRINT("ESRT failed to obtain the FMP image info\n");
269 		goto out;
270 	}
271 
272 	/*
273 	 * Iterate over all the FW images in the FMP.
274 	 */
275 	for (u32 desc_idx = 0; desc_idx < desc_count; desc_idx++) {
276 		struct efi_firmware_image_descriptor *cur_img_info =
277 			(struct efi_firmware_image_descriptor *)
278 			((uintptr_t)img_info + desc_idx * desc_size);
279 
280 		/*
281 		 * Obtain the ESRT entry for the FW image with fw_class
282 		 * equal to cur_img_info->image_type_id.
283 		 */
284 		entry = esrt_find_entry(&cur_img_info->image_type_id);
285 
286 		if (entry) {
287 			ret = efi_esrt_image_info_to_entry(cur_img_info, entry,
288 							   desc_version,
289 							   image_type, flags);
290 			if (ret != EFI_SUCCESS)
291 				EFI_PRINT("ESRT entry mismatches image_type\n");
292 
293 		} else {
294 			EFI_PRINT("ESRT failed to add entry for %pUl\n",
295 				  &cur_img_info->image_type_id);
296 			continue;
297 		}
298 	}
299 
300 out:
301 	efi_free_pool(img_info);
302 	return EFI_SUCCESS;
303 }
304 
305 /**
306  * efi_esrt_populate() - Populates the ESRT entries from the FMP instances
307  * present in the system.
308  * If an ESRT already exists, the old ESRT is replaced in the system table.
309  * The memory of the old ESRT is deallocated.
310  *
311  * Return:
312  * - EFI_SUCCESS if the ESRT is correctly created
313  * - error code otherwise.
314  */
efi_esrt_populate(void)315 efi_status_t efi_esrt_populate(void)
316 {
317 	efi_handle_t *base_handle = NULL;
318 	efi_handle_t *it_handle;
319 	efi_uintn_t no_handles = 0;
320 	struct efi_firmware_management_protocol *fmp;
321 	efi_status_t ret;
322 	u32 num_entries = 0;
323 	struct efi_handler *handler;
324 
325 	/*
326 	 * Obtain the number of registered FMP handles.
327 	 */
328 	ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
329 						&efi_guid_firmware_management_protocol,
330 						NULL, &no_handles,
331 						(efi_handle_t **)&base_handle));
332 
333 	if (ret != EFI_SUCCESS) {
334 		EFI_PRINT("ESRT There are no FMP instances\n");
335 
336 		ret = efi_esrt_allocate_install(0);
337 		if (ret != EFI_SUCCESS) {
338 			EFI_PRINT("ESRT failed to create table with 0 entries\n");
339 			return ret;
340 		}
341 		return EFI_SUCCESS;
342 	}
343 
344 	EFI_PRINT("ESRT populate esrt from (%zd) available FMP handles\n",
345 		  no_handles);
346 
347 	/*
348 	 * Iterate over all FMPs to determine an upper bound on the number of
349 	 * ESRT entries.
350 	 */
351 	it_handle = base_handle;
352 	for (u32 idx = 0; idx < no_handles; idx++, it_handle++) {
353 		struct efi_firmware_image_descriptor *img_info = NULL;
354 		size_t info_size = 0;
355 		u32 desc_version = 0;
356 		u8 desc_count = 0;
357 		size_t desc_size = 0;
358 		u32 package_version;
359 		u16 *package_version_name;
360 
361 		ret = efi_search_protocol(*it_handle,
362 					  &efi_guid_firmware_management_protocol,
363 					  &handler);
364 
365 		if (ret != EFI_SUCCESS) {
366 			EFI_PRINT("ESRT Unable to find FMP handle (%u)\n",
367 				  idx);
368 			goto out;
369 		}
370 		fmp = handler->protocol_interface;
371 
372 		ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, NULL,
373 						   &desc_version, &desc_count,
374 						   &desc_size, &package_version,
375 						   &package_version_name));
376 
377 		if (ret != EFI_BUFFER_TOO_SMALL) {
378 			/*
379 			 * An input of info_size=0 should always lead
380 			 * fmp->get_image_info to return BUFFER_TO_SMALL.
381 			 */
382 			EFI_PRINT("ESRT erroneous FMP implementation\n");
383 			ret = EFI_INVALID_PARAMETER;
384 			goto out;
385 		}
386 
387 		ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
388 					(void **)&img_info);
389 		if (ret != EFI_SUCCESS) {
390 			EFI_PRINT("ESRT failed to allocate memory for image info\n");
391 			goto out;
392 		}
393 
394 		/*
395 		 * Calls to a FMP get_image_info method do not return the
396 		 * desc_count value if the return status differs from EFI_SUCCESS.
397 		 * We need to repeat the call to get_image_info with a properly
398 		 * sized buffer in order to obtain the real number of images
399 		 * handled by the FMP.
400 		 */
401 		ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
402 						   &desc_version, &desc_count,
403 						   &desc_size, &package_version,
404 						   &package_version_name));
405 
406 		if (ret != EFI_SUCCESS) {
407 			EFI_PRINT("ESRT failed to obtain image info from FMP\n");
408 			efi_free_pool(img_info);
409 			goto out;
410 		}
411 
412 		num_entries += desc_count;
413 
414 		efi_free_pool(img_info);
415 	}
416 
417 	EFI_PRINT("ESRT create table with %u entries\n", num_entries);
418 	/*
419 	 * Allocate an ESRT with the sufficient number of entries to accommodate
420 	 * all the FMPs in the system.
421 	 */
422 	ret = efi_esrt_allocate_install(num_entries);
423 	if (ret != EFI_SUCCESS) {
424 		EFI_PRINT("ESRT failed to initialize table\n");
425 		goto out;
426 	}
427 
428 	/*
429 	 * Populate the ESRT entries with all existing FMP.
430 	 */
431 	it_handle = base_handle;
432 	for (u32 idx = 0; idx < no_handles; idx++, it_handle++) {
433 		ret = efi_search_protocol(*it_handle,
434 					  &efi_guid_firmware_management_protocol,
435 					  &handler);
436 
437 		if (ret != EFI_SUCCESS) {
438 			EFI_PRINT("ESRT unable to find FMP handle (%u)\n",
439 				  idx);
440 			break;
441 		}
442 		fmp = handler->protocol_interface;
443 
444 		ret = efi_esrt_add_from_fmp(fmp);
445 		if (ret != EFI_SUCCESS)
446 			EFI_PRINT("ESRT failed to add FMP to the table\n");
447 	}
448 
449 out:
450 
451 	efi_free_pool(base_handle);
452 
453 	return ret;
454 }
455 
456 /**
457  * efi_esrt_new_fmp_notify() - Callback for the EVT_NOTIFY_SIGNAL event raised
458  * when a new FMP protocol instance is registered in the system.
459  */
efi_esrt_new_fmp_notify(struct efi_event * event,void * context)460 static void EFIAPI efi_esrt_new_fmp_notify(struct efi_event *event,
461 					   void *context)
462 {
463 	efi_status_t ret;
464 
465 	EFI_ENTRY();
466 
467 	ret = efi_esrt_populate();
468 	if (ret != EFI_SUCCESS)
469 		EFI_PRINT("ESRT failed to populate ESRT entry\n");
470 
471 	EFI_EXIT(ret);
472 }
473 
474 /**
475  * efi_esrt_register() - Install the ESRT system table.
476  *
477  * Return: status code
478  */
efi_esrt_register(void)479 efi_status_t efi_esrt_register(void)
480 {
481 	struct efi_event *ev = NULL;
482 	void *registration;
483 	efi_status_t ret;
484 
485 	EFI_PRINT("ESRT creation start\n");
486 
487 	ret = efi_esrt_populate();
488 	if (ret != EFI_SUCCESS) {
489 		EFI_PRINT("ESRT failed to initiate the table\n");
490 		return ret;
491 	}
492 
493 	ret = efi_create_event(EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
494 			       efi_esrt_new_fmp_notify, NULL, NULL, &ev);
495 	if (ret != EFI_SUCCESS) {
496 		EFI_PRINT("ESRT failed to create event\n");
497 		return ret;
498 	}
499 
500 	ret = EFI_CALL(efi_register_protocol_notify(&efi_guid_firmware_management_protocol,
501 						    ev, &registration));
502 	if (ret != EFI_SUCCESS) {
503 		EFI_PRINT("ESRT failed to register FMP callback\n");
504 		return ret;
505 	}
506 
507 	EFI_PRINT("ESRT table created\n");
508 
509 	return ret;
510 }
511