1 // SPDX-License-Identifier: GPL-2.0-only
3 * EFI application ESRT tables support
5 * Copyright (C) 2021 Arm Ltd.
9 #include <efi_loader.h>
14 const efi_guid_t efi_esrt_guid = EFI_SYSTEM_RESOURCE_TABLE_GUID;
16 static struct efi_system_resource_table *esrt;
18 #define EFI_ESRT_VERSION 1
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.
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
33 * - EFI_SUCCESS if the entry is correctly updated
34 * - EFI_INVALID_PARAMETER if entry does not match image_type_id in @img_info.
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)
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;
47 entry->fw_version = img_info->version;
49 entry->fw_type = image_type;
50 entry->capsule_flags = flags;
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.
57 if (desc_version >= 2)
58 entry->lowest_supported_fw_version =
59 img_info->lowest_supported_image_version;
61 entry->lowest_supported_fw_version = 0;
64 * The fields last_attempt_version and last_attempt_status
65 * are only present on image info structure of version 3 or
67 * See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI.
69 if (desc_version >= 3) {
70 entry->last_attempt_version =
71 img_info->last_attempt_version;
73 entry->last_attempt_status =
74 img_info->last_attempt_status;
76 entry->last_attempt_version = 0;
77 entry->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
84 * efi_esrt_entries_to_size() - Obtain the bytes used by an ESRT
85 * datastructure with @num_entries.
87 * @num_entries: the number of entries in the ESRT.
89 * Return: the number of bytes an ESRT with @num_entries occupies in memory.
92 inline u32 efi_esrt_entries_to_size(u32 num_entries)
94 u32 esrt_size = sizeof(struct efi_system_resource_table) +
95 num_entries * sizeof(struct efi_system_resource_entry);
101 * efi_esrt_allocate_install() - Allocates @num_entries for the ESRT and
102 * performs basic ESRT initialization.
104 * @num_entries: the number of entries that the ESRT will hold.
107 * - pointer to the ESRT if successful.
111 efi_status_t efi_esrt_allocate_install(u32 num_entries)
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;
118 /* Reserve num_pages for ESRT */
119 ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, size,
122 if (ret != EFI_SUCCESS) {
123 EFI_PRINT("ESRT cannot allocate memory for %u entries (%u bytes)\n",
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;
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");
140 /* If there was a previous ESRT, deallocate its memory now. */
142 ret = efi_free_pool(esrt);
150 * esrt_find_entry() - Obtain the ESRT entry for the image with GUID
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.
157 * @img_fw_class: the GUID of the FW image which ESRT entry we want to obtain.
160 * - A pointer to the ESRT entry for the image with GUID img_fw_class,
162 * - there is no more space in the ESRT,
163 * - ESRT is not initialized,
166 struct efi_system_resource_entry *esrt_find_entry(efi_guid_t *img_fw_class)
170 struct efi_system_resource_entry *entry;
173 EFI_PRINT("ESRT access before initialized\n");
177 filled_entries = esrt->fw_resource_count;
178 entry = esrt->entries;
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 %pUs at index %u\n",
189 max_entries = esrt->fw_resource_count_max;
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.
194 if (filled_entries == max_entries) {
195 EFI_PRINT("ESRT full, this should not happen\n");
200 * This is a new entry for a fw image, increment the element
201 * number in the table and set the fw_class field.
203 esrt->fw_resource_count++;
204 entry[filled_entries].fw_class = *img_fw_class;
205 EFI_PRINT("ESRT allocated new entry for image %pUs at index %u\n",
206 img_fw_class, filled_entries);
208 return &entry[filled_entries];
212 * efi_esrt_add_from_fmp() - Populates a sequence of ESRT entries from the FW
215 * @fmp: the FMP instance from which FW images are added to the ESRT
218 * - EFI_SUCCESS if all the FW images in the FMP are added to the ESRT
219 * - Error status otherwise
222 efi_status_t efi_esrt_add_from_fmp(struct efi_firmware_management_protocol *fmp)
224 struct efi_system_resource_entry *entry = NULL;
225 size_t info_size = 0;
226 struct efi_firmware_image_descriptor *img_info = NULL;
231 u16 *package_version_name;
232 efi_status_t ret = EFI_SUCCESS;
235 * TODO: set the field image_type depending on the FW image type
236 * defined in a platform basis.
238 u32 image_type = ESRT_FW_TYPE_UNKNOWN;
240 /* TODO: set the capsule flags as a function of the FW image type. */
243 ret = EFI_CALL(fmp->get_image_info(fmp, &info_size, img_info,
244 &desc_version, &desc_count,
245 &desc_size, NULL, NULL));
247 if (ret != EFI_BUFFER_TOO_SMALL) {
249 * An input of info_size=0 should always lead
250 * fmp->get_image_info to return BUFFER_TO_SMALL.
252 EFI_PRINT("Erroneous FMP implementation\n");
253 return EFI_INVALID_PARAMETER;
256 ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
258 if (ret != EFI_SUCCESS) {
259 EFI_PRINT("ESRT failed to allocate memory for image info.\n");
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");
273 * Iterate over all the FW images in the FMP.
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);
281 * Obtain the ESRT entry for the FW image with fw_class
282 * equal to cur_img_info->image_type_id.
284 entry = esrt_find_entry(&cur_img_info->image_type_id);
287 ret = efi_esrt_image_info_to_entry(cur_img_info, entry,
290 if (ret != EFI_SUCCESS)
291 EFI_PRINT("ESRT entry mismatches image_type\n");
294 EFI_PRINT("ESRT failed to add entry for %pUs\n",
295 &cur_img_info->image_type_id);
301 efi_free_pool(img_info);
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.
312 * - EFI_SUCCESS if the ESRT is correctly created
313 * - error code otherwise.
315 efi_status_t efi_esrt_populate(void)
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;
323 struct efi_handler *handler;
326 * Obtain the number of registered FMP handles.
328 ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
329 &efi_guid_firmware_management_protocol,
331 (efi_handle_t **)&base_handle));
333 if (ret != EFI_SUCCESS) {
334 EFI_PRINT("ESRT There are no FMP instances\n");
336 ret = efi_esrt_allocate_install(0);
337 if (ret != EFI_SUCCESS) {
338 EFI_PRINT("ESRT failed to create table with 0 entries\n");
344 EFI_PRINT("ESRT populate esrt from (%zd) available FMP handles\n",
348 * Iterate over all FMPs to determine an upper bound on the number of
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;
357 size_t desc_size = 0;
359 u16 *package_version_name;
361 ret = efi_search_protocol(*it_handle,
362 &efi_guid_firmware_management_protocol,
365 if (ret != EFI_SUCCESS) {
366 EFI_PRINT("ESRT Unable to find FMP handle (%u)\n",
370 fmp = handler->protocol_interface;
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));
377 if (ret != EFI_BUFFER_TOO_SMALL) {
379 * An input of info_size=0 should always lead
380 * fmp->get_image_info to return BUFFER_TO_SMALL.
382 EFI_PRINT("ESRT erroneous FMP implementation\n");
383 ret = EFI_INVALID_PARAMETER;
387 ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
389 if (ret != EFI_SUCCESS) {
390 EFI_PRINT("ESRT failed to allocate memory for image info\n");
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.
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));
406 if (ret != EFI_SUCCESS) {
407 EFI_PRINT("ESRT failed to obtain image info from FMP\n");
408 efi_free_pool(img_info);
412 num_entries += desc_count;
414 efi_free_pool(img_info);
417 EFI_PRINT("ESRT create table with %u entries\n", num_entries);
419 * Allocate an ESRT with the sufficient number of entries to accommodate
420 * all the FMPs in the system.
422 ret = efi_esrt_allocate_install(num_entries);
423 if (ret != EFI_SUCCESS) {
424 EFI_PRINT("ESRT failed to initialize table\n");
429 * Populate the ESRT entries with all existing FMP.
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,
437 if (ret != EFI_SUCCESS) {
438 EFI_PRINT("ESRT unable to find FMP handle (%u)\n",
442 fmp = handler->protocol_interface;
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");
451 efi_free_pool(base_handle);
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.
460 static void EFIAPI efi_esrt_new_fmp_notify(struct efi_event *event,
467 ret = efi_esrt_populate();
468 if (ret != EFI_SUCCESS)
469 EFI_PRINT("ESRT failed to populate ESRT entry\n");
475 * efi_esrt_register() - Install the ESRT system table.
477 * Return: status code
479 efi_status_t efi_esrt_register(void)
481 struct efi_event *ev = NULL;
485 EFI_PRINT("ESRT creation start\n");
487 ret = efi_esrt_populate();
488 if (ret != EFI_SUCCESS) {
489 EFI_PRINT("ESRT failed to initiate the table\n");
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");
500 ret = EFI_CALL(efi_register_protocol_notify(&efi_guid_firmware_management_protocol,
502 if (ret != EFI_SUCCESS) {
503 EFI_PRINT("ESRT failed to register FMP callback\n");
507 EFI_PRINT("ESRT table created\n");