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