// SPDX-License-Identifier: GPL-2.0-or-later /* * EFI debug support * * Copyright (c) 2025 Ying-Chun Liu, Linaro Ltd. */ #include #include #include struct efi_system_table_pointer __efi_runtime_data * systab_pointer = NULL; struct efi_debug_image_info_table_header efi_m_debug_info_table_header = { 0, 0, NULL }; /* efi_m_max_table_entries is the maximum entries allocated for * the efi_m_debug_info_table_header.efi_debug_image_info_table. */ static u32 efi_m_max_table_entries; #define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof(union efi_debug_image_info *)) /** * efi_initialize_system_table_pointer() - Initialize system table pointer * * Return: status code */ efi_status_t efi_initialize_system_table_pointer(void) { /* Allocate efi_system_table_pointer structure with 4MB alignment. */ systab_pointer = efi_alloc_aligned_pages(sizeof(struct efi_system_table_pointer), EFI_RUNTIME_SERVICES_DATA, SZ_4M); if (!systab_pointer) { log_err("Installing EFI system table pointer failed\n"); return EFI_OUT_OF_RESOURCES; } systab_pointer->crc32 = 0; systab_pointer->signature = EFI_SYSTEM_TABLE_SIGNATURE; systab_pointer->efi_system_table_base = (uintptr_t)&systab; systab_pointer->crc32 = crc32(0, (const unsigned char *)systab_pointer, sizeof(struct efi_system_table_pointer)); return EFI_SUCCESS; } /** * efi_core_new_debug_image_info_entry() - Add a new efi_loaded_image structure to the * efi_debug_image_info table. * * @image_info_type: type of debug image information * @loaded_image: pointer to the loaded image protocol for the image * being loaded * @image_handle: image handle for the image being loaded * * Re-Allocates the table if it's not large enough to accommodate another * entry. * * Return: status code **/ efi_status_t efi_core_new_debug_image_info_entry(u32 image_info_type, struct efi_loaded_image *loaded_image, efi_handle_t image_handle) { union efi_debug_image_info **table; u32 index; u32 table_size; efi_status_t ret; /* Set the flag indicating that we're in the process of updating * the table. */ efi_m_debug_info_table_header.update_status |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; table = &efi_m_debug_info_table_header.efi_debug_image_info_table; if (efi_m_debug_info_table_header.table_size >= efi_m_max_table_entries) { /* table is full, re-allocate the buffer increasing the size * by 4 KiB. */ table_size = efi_m_max_table_entries * EFI_DEBUG_TABLE_ENTRY_SIZE; ret = efi_realloc((void **)table, table_size + EFI_PAGE_SIZE); if (ret != EFI_SUCCESS) { efi_m_debug_info_table_header.update_status &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; return ret; } /* Enlarge the max table entries and set the first empty * entry index to be the original max table entries. */ efi_m_max_table_entries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE; } /* We always put the next entry at the end of the currently consumed * table (i.e. first free entry) */ index = efi_m_debug_info_table_header.table_size; /* Allocate data for new entry. */ ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, sizeof(union efi_debug_image_info), (void **)(&(*table)[index].normal_image)); if (ret == EFI_SUCCESS && (*table)[index].normal_image) { /* Update the entry. */ (*table)[index].normal_image->image_info_type = image_info_type; (*table)[index].normal_image->loaded_image_protocol_instance = loaded_image; (*table)[index].normal_image->image_handle = image_handle; /* Increase the number of EFI_DEBUG_IMAGE_INFO elements and * set the efi_m_debug_info_table_header in modified status. */ efi_m_debug_info_table_header.table_size++; efi_m_debug_info_table_header.update_status |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED; } else { log_err("Adding new efi_debug_image_info failed\n"); return ret; } efi_m_debug_info_table_header.update_status &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; return EFI_SUCCESS; } /** * efi_core_remove_debug_image_info_entry() - Remove an efi_debug_image_info entry. * * @image_handle: image handle for the image being removed **/ void efi_core_remove_debug_image_info_entry(efi_handle_t image_handle) { union efi_debug_image_info *table; u32 index; efi_m_debug_info_table_header.update_status |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; table = efi_m_debug_info_table_header.efi_debug_image_info_table; for (index = 0; index < efi_m_max_table_entries; index++) { if (table[index].normal_image && table[index].normal_image->image_handle == image_handle) { /* Found a match. Free up the table entry. * Move the tail of the table one slot to the front. */ efi_free_pool(table[index].normal_image); memmove(&table[index], &table[index + 1], (efi_m_debug_info_table_header.table_size - index - 1) * EFI_DEBUG_TABLE_ENTRY_SIZE); /* Decrease the number of EFI_DEBUG_IMAGE_INFO * elements and set the efi_m_debug_info_table_header * in modified status. */ efi_m_debug_info_table_header.table_size--; table[efi_m_debug_info_table_header.table_size].normal_image = NULL; efi_m_debug_info_table_header.update_status |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED; break; } } efi_m_debug_info_table_header.update_status &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; }