From f517d93842ad733d8df485d8255a3649c8ac517a Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 19 Jun 2025 10:34:00 +0200 Subject: disk: efi: expose the part_get_gpt_pte() helper function This function will be used by the EFI application disk support code to provide data required by the EFI_PARTITION_INFORMATION_PROTOCOL. Signed-off-by: Javier Martinez Canillas Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- include/part.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'include') diff --git a/include/part.h b/include/part.h index 7075b2cb116..b3a3362b2af 100644 --- a/include/part.h +++ b/include/part.h @@ -647,6 +647,20 @@ int gpt_verify_partitions(struct blk_desc *desc, */ int get_disk_guid(struct blk_desc *desc, char *guid); +/** + * part_get_gpt_pte() - Get the GPT partition table entry of a partition + * + * This function reads the GPT partition table entry (PTE) for a given + * block device and partition number. + * + * @desc: block device descriptor + * @part: partition number for which to return the PTE + * @gpt_e: GPT partition table entry + * + * Return: 0 on success, otherwise error + */ +int part_get_gpt_pte(struct blk_desc *desc, int part, gpt_entry *gpt_e); + #endif #if CONFIG_IS_ENABLED(DOS_PARTITION) -- cgit v1.3.1 From 2fdfb802e30a1fbd65a830a283d7bd87631f08c0 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 19 Jun 2025 10:34:01 +0200 Subject: efi_loader: disk: add EFI_PARTITION_INFO_PROTOCOL support The UEFI 2.10 specification mentions that this protocol shall be installed along with EFI_BLOCK_IO_PROTOCOL. It provides cached partition information for MBR and GPT partition types. This patch just implements support for GPT partition types. The legacy MBR partition types is only needed for backward compatibility and can be added as a follow-up if needed, to make it fully compliant with the EFI spec. Signed-off-by: Javier Martinez Canillas Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- include/part_efi.h | 20 ++++++++++++++++++++ lib/efi_loader/efi_disk.c | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/part_efi.h b/include/part_efi.h index 59b7895b8a2..fb402df6f13 100644 --- a/include/part_efi.h +++ b/include/part_efi.h @@ -138,4 +138,24 @@ typedef struct _legacy_mbr { __le16 signature; } __packed legacy_mbr; +#define EFI_PARTITION_INFO_PROTOCOL_GUID \ + EFI_GUID(0x8cf2f62c, 0xbc9b, 0x4821, 0x80, \ + 0x8d, 0xec, 0x9e, 0xc4, 0x21, 0xa1, 0xa0) + +#define EFI_PARTITION_INFO_PROTOCOL_REVISION 0x0001000 +#define PARTITION_TYPE_OTHER 0x00 +#define PARTITION_TYPE_MBR 0x01 +#define PARTITION_TYPE_GPT 0x02 + +struct efi_partition_info { + u32 revision; + u32 type; + u8 system; + u8 reserved[7]; + union { + struct partition mbr; + gpt_entry gpt; + } info; +} __packed; + #endif /* _DISK_PART_EFI_H */ diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 47b583cc5e1..130c4db9606 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -26,6 +26,7 @@ struct efi_system_partition efi_system_partition = { const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID; const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID; +const efi_guid_t efi_partition_info_guid = EFI_PARTITION_INFO_PROTOCOL_GUID; /** * struct efi_disk_obj - EFI disk object @@ -35,6 +36,7 @@ const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID; * @media: block I/O media information * @dp: device path to the block device * @volume: simple file system protocol of the partition + * @info: EFI partition info protocol interface */ struct efi_disk_obj { struct efi_object header; @@ -42,6 +44,7 @@ struct efi_disk_obj { struct efi_block_io_media media; struct efi_device_path *dp; struct efi_simple_file_system_protocol *volume; + struct efi_partition_info info; }; /** @@ -426,6 +429,7 @@ static efi_status_t efi_disk_add_dev( /* Fill in object data */ if (part_info) { struct efi_device_path *node = efi_dp_part_node(desc, part); + struct efi_partition_info *info = &diskobj->info; struct efi_handler *handler; void *protocol_interface; @@ -454,18 +458,48 @@ static efi_status_t efi_disk_add_dev( goto error; } + info->revision = EFI_PARTITION_INFO_PROTOCOL_REVISION; + + switch (desc->part_type) { +#if CONFIG_IS_ENABLED(EFI_PARTITION) + case PART_TYPE_EFI: + info->type = PARTITION_TYPE_GPT; + ret = part_get_gpt_pte(desc, part, &info->info.gpt); + if (ret) { + log_debug("get PTE for part %d failed %ld\n", + part, ret); + goto error; + } + break; +#endif +#if CONFIG_IS_ENABLED(DOS_PARTITION) + case PART_TYPE_DOS: + info->type = PARTITION_TYPE_MBR; + + /* TODO: implement support for MBR partition types */ + log_debug("EFI_PARTITION_INFO_PROTOCOL doesn't support MBR\n"); + break; +#endif + default: + info->type = PARTITION_TYPE_OTHER; + break; + } + diskobj->dp = efi_dp_append_node(dp_parent, node); efi_free_pool(node); diskobj->media.last_block = part_info->size - 1; - if (part_info->bootable & PART_EFI_SYSTEM_PARTITION) + if (part_info->bootable & PART_EFI_SYSTEM_PARTITION) { esp_guid = &efi_system_partition_guid; + info->system = 1; + } + } else { diskobj->dp = efi_dp_from_part(desc, part); diskobj->media.last_block = desc->lba - 1; } /* - * Install the device path and the block IO protocol. + * Install the device path, the block IO and partition info protocols. * * InstallMultipleProtocolInterfaces() checks if the device path is * already installed on an other handle and returns EFI_ALREADY_STARTED @@ -476,6 +510,7 @@ static efi_status_t efi_disk_add_dev( &handle, &efi_guid_device_path, diskobj->dp, &efi_block_io_guid, &diskobj->ops, + &efi_partition_info_guid, &diskobj->info, /* * esp_guid must be last entry as it * can be NULL. Its interface is NULL. -- cgit v1.3.1 From ed004a260acdb196c8f36dffdb4c3b428f215616 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Thu, 3 Jul 2025 12:13:07 +0530 Subject: cmd: eficonfig: add support for URI device path based boot options The eficonfig command provides a menu based interface for maintenance of the EFI boot options. Add support for adding a URI based boot option. This boot option can then be used for HTTP boot. Signed-off-by: Sughosh Ganu Reviewed-by: Ilias Apalodimas Tested-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- cmd/eficonfig.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++--- include/efi_config.h | 2 + 2 files changed, 140 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c index 6e14d34a6bd..8ac0fb98e02 100644 --- a/cmd/eficonfig.c +++ b/cmd/eficonfig.c @@ -35,6 +35,7 @@ static int avail_row; #define EFICONFIG_DESCRIPTION_MAX 32 #define EFICONFIG_OPTIONAL_DATA_MAX 64 +#define EFICONFIG_URI_MAX 512 #define EFICONFIG_MENU_HEADER_ROW_NUM 3 #define EFICONFIG_MENU_DESC_ROW_NUM 5 @@ -538,6 +539,40 @@ struct efi_device_path *eficonfig_create_device_path(struct efi_device_path *dp_ return dp; } +/** + * eficonfig_create_uri_device_path() - Create an URI based device path + * @uri_str: URI string to be added to the device path + * + * Take the u16 string, convert it to a u8 string, and create a URI + * device path. This will be used for the EFI HTTP boot. + * + * Return: pointer to the URI device path on success, NULL on failure + */ +static struct efi_device_path *eficonfig_create_uri_device_path(u16 *uri_str) +{ + char *pos, *p; + u32 len = 0; + efi_uintn_t uridp_len; + struct efi_device_path_uri *uridp; + + len = utf16_utf8_strlen(uri_str); + + uridp_len = sizeof(struct efi_device_path) + len + 1; + uridp = efi_alloc(uridp_len + sizeof(EFI_DP_END)); + if (!uridp) + return NULL; + + uridp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE; + uridp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_URI; + uridp->dp.length = uridp_len; + p = (char *)&uridp->uri; + utf16_utf8_strcpy(&p, uri_str); + pos = (char *)uridp + uridp_len; + memcpy(pos, &EFI_DP_END, sizeof(EFI_DP_END)); + + return &uridp->dp; +} + /** * eficonfig_file_selected() - handler of file selection * @@ -983,6 +1018,22 @@ static efi_status_t eficonfig_boot_add_optional_data(void *data) " enter optional data:"); } +/** + * eficonfig_boot_add_uri() - handle user input for HTTP Boot URI + * + * @data: pointer to the internal boot option structure + * Return: status code + */ +static efi_status_t eficonfig_boot_add_uri(void *data) +{ + struct eficonfig_select_file_info *file_info = data; + + return handle_user_input(file_info->uri, EFICONFIG_URI_MAX, 24, + "\n ** Edit URI **\n" + "\n" + " enter HTTP Boot URI:"); +} + /** * eficonfig_boot_edit_save() - handler to save the boot option * @@ -998,7 +1049,8 @@ static efi_status_t eficonfig_boot_edit_save(void *data) bo->edit_completed = false; return EFI_NOT_READY; } - if (u16_strlen(bo->file_info.current_path) == 0) { + if (u16_strlen(bo->file_info.current_path) == 0 && + u16_strlen(bo->file_info.uri) == 0) { eficonfig_print_msg("File is not selected!"); bo->edit_completed = false; return EFI_NOT_READY; @@ -1024,9 +1076,19 @@ efi_status_t eficonfig_process_clear_file_selection(void *data) file_info->current_path[0] = u'\0'; file_info->dp_volume = NULL; + if (file_info->uri) + file_info->uri[0] = u'\0'; + return EFI_ABORTED; } +static struct eficonfig_item select_boot_file_menu_items[] = { + {"Select File", eficonfig_process_select_file}, + {"Enter URI", eficonfig_boot_add_uri}, + {"Clear", eficonfig_process_clear_file_selection}, + {"Quit", eficonfig_process_quit}, +}; + static struct eficonfig_item select_file_menu_items[] = { {"Select File", eficonfig_process_select_file}, {"Clear", eficonfig_process_clear_file_selection}, @@ -1042,16 +1104,30 @@ static struct eficonfig_item select_file_menu_items[] = { efi_status_t eficonfig_process_show_file_option(void *data) { efi_status_t ret; + unsigned int menu_count; struct efimenu *efi_menu; + struct eficonfig_item *menu_items; + struct eficonfig_select_file_info *file_info = data; + + menu_items = file_info->uri ? select_boot_file_menu_items : + select_file_menu_items; + + menu_count = file_info->uri ? + ARRAY_SIZE(select_boot_file_menu_items) : + ARRAY_SIZE(select_file_menu_items); + + menu_items[0].data = data; + menu_items[1].data = data; + menu_items[2].data = data; - select_file_menu_items[0].data = data; - select_file_menu_items[1].data = data; - efi_menu = eficonfig_create_fixed_menu(select_file_menu_items, - ARRAY_SIZE(select_file_menu_items)); + efi_menu = eficonfig_create_fixed_menu(menu_items, menu_count); if (!efi_menu) return EFI_OUT_OF_RESOURCES; - ret = eficonfig_process_common(efi_menu, " ** Update File **", + ret = eficonfig_process_common(efi_menu, + file_info->uri ? + " ** Update File/URI **" : + " ** Update File **", eficonfig_menu_desc, eficonfig_display_statusline, eficonfig_print_entry, @@ -1121,6 +1197,14 @@ out: file_info->current_path[len] = u'\0'; file_info->current_volume = tmp->current_volume; file_info->dp_volume = tmp->dp_volume; + + /* + * File being selected, set the URI string to + * null so that the file gets picked as the + * boot image. + */ + if (file_info->uri) + file_info->uri[0] = u'\0'; } list_for_each_safe(pos, n, &tmp->filepath_list) { @@ -1224,6 +1308,12 @@ static efi_status_t prepare_file_selection_entry(struct efimenu *efi_menu, char efi_handle_t handle; char *devname; + /* Check for URI based boot file */ + if (file_info->uri && utf16_utf8_strlen(file_info->uri)) + return create_boot_option_entry(efi_menu, title, file_info->uri, + eficonfig_process_show_file_option, + file_info); + devname = calloc(1, EFICONFIG_VOLUME_PATH_MAX + 1); if (!devname) return EFI_OUT_OF_RESOURCES; @@ -1340,6 +1430,27 @@ out: return ret; } +/** + * fill_dp_uri() - copy the URI string in the device path + * @dp: pointer to the URI device path + * @uri_str: URI string to be copied + * + * Copy the passed URI string to the URI device path. This + * requires utf8_utf16_strcpy() to copy the u16 string to + * the u8 array in the device path structure. + * + * Return: None + */ +static void fill_dp_uri(struct efi_device_path *dp, u16 **uri_str) +{ + u16 *p = *uri_str; + struct efi_device_path_uri *uridp; + + uridp = (struct efi_device_path_uri *)dp; + + utf8_utf16_strcpy(&p, uridp->uri); +} + /** * fill_file_info() - fill the file info from efi_device_path structure * @@ -1392,10 +1503,13 @@ static efi_status_t eficonfig_edit_boot_option(u16 *varname, struct eficonfig_bo size_t len; efi_status_t ret; char *tmp = NULL, *p; + u16 *current_path = NULL; struct efi_load_option lo = {0}; efi_uintn_t dp_size; struct efi_device_path *dp = NULL; efi_uintn_t size = load_option_size; + struct efi_device_path *dp_volume = NULL; + struct efi_device_path *uri_dp = NULL; struct efi_device_path *device_dp = NULL; struct efi_device_path *initrd_dp = NULL; struct efi_device_path *fdt_dp = NULL; @@ -1464,6 +1578,12 @@ static efi_status_t eficonfig_edit_boot_option(u16 *varname, struct eficonfig_bo goto out; } + bo->file_info.uri = calloc(1, EFICONFIG_URI_MAX * sizeof(u16)); + if (!bo->file_info.uri) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + /* copy the preset value */ if (load_option) { ret = efi_deserialize_load_option(&lo, load_option, &size); @@ -1481,7 +1601,10 @@ static efi_status_t eficonfig_edit_boot_option(u16 *varname, struct eficonfig_bo u16_strcpy(bo->description, lo.label); /* EFI image file path is a first instance */ - if (lo.file_path) + if (lo.file_path && EFI_DP_TYPE(lo.file_path, MESSAGING_DEVICE, + MSG_URI)) + fill_dp_uri(lo.file_path, &bo->file_info.uri); + else if (lo.file_path) fill_file_info(lo.file_path, &bo->file_info, device_dp); /* Initrd file path (optional) is placed at second instance. */ @@ -1512,6 +1635,9 @@ static efi_status_t eficonfig_edit_boot_option(u16 *varname, struct eficonfig_bo goto out; } + if (utf16_utf8_strlen(bo->file_info.uri)) + uri_dp = eficonfig_create_uri_device_path(bo->file_info.uri); + if (bo->initrd_info.dp_volume) { dp = eficonfig_create_device_path(bo->initrd_info.dp_volume, bo->initrd_info.current_path); @@ -1536,7 +1662,10 @@ static efi_status_t eficonfig_edit_boot_option(u16 *varname, struct eficonfig_bo efi_free_pool(dp); } - dp = eficonfig_create_device_path(bo->file_info.dp_volume, bo->file_info.current_path); + dp_volume = bo->file_info.dp_volume; + current_path = bo->file_info.current_path; + dp = uri_dp ? + uri_dp : eficonfig_create_device_path(dp_volume, current_path); if (!dp) { ret = EFI_OUT_OF_RESOURCES; goto out; @@ -1560,6 +1689,7 @@ out: free(tmp); free(bo->optional_data); free(bo->description); + free(bo->file_info.uri); free(bo->file_info.current_path); free(bo->initrd_info.current_path); free(bo->fdt_info.current_path); diff --git a/include/efi_config.h b/include/efi_config.h index d7c1601137e..23211e799fc 100644 --- a/include/efi_config.h +++ b/include/efi_config.h @@ -82,6 +82,7 @@ struct eficonfig_item { * @current_volume: pointer to the efi_simple_file_system_protocol * @dp_volume: pointer to device path of the selected device * @current_path: pointer to the selected file path string + * @uri: URI for HTTP Boot * @filepath_list: list_head structure for file path list * @file_selectred: flag indicates file selecting status */ @@ -89,6 +90,7 @@ struct eficonfig_select_file_info { struct efi_simple_file_system_protocol *current_volume; struct efi_device_path *dp_volume; u16 *current_path; + u16 *uri; struct list_head filepath_list; bool file_selected; }; -- cgit v1.3.1 From aaf7be96c2c14aa190d39e50fa3606389eafda8e Mon Sep 17 00:00:00 2001 From: "Ying-Chun Liu (PaulLiu)" Date: Thu, 3 Jul 2025 07:28:07 +0100 Subject: efi: add EFI_SYSTEM_TABLE_POINTER for debug Add EFI_SYSTEM_TABLE_POINTER structure for remote debugger to locate the address of EFI_SYSTEM_TABLE. This feature is described in UEFI SPEC version 2.10. Section 18.4.2. The implementation ensures support for hardware-assisted debugging and provides a standardized mechanism for debuggers to discover the EFI system table. Cc: Peter Robinson Cc: Simon Glass Signed-off-by: Ying-Chun Liu (PaulLiu) Reviewed-by: Ilias Apalodimas Tested-by: Heinrich Schuchardt Reviewed-by: Heinrich Schuchardt # change memset(systab_pointer, 0 ...) -> systab_pointer->crc32 = 0; Signed-off-by: Ilias Apalodimas --- include/efi_api.h | 16 +++++++++++++++ include/efi_loader.h | 2 ++ lib/efi_loader/Kconfig | 9 +++++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_debug_support.c | 40 ++++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_setup.c | 7 +++++++ 6 files changed, 75 insertions(+) create mode 100644 lib/efi_loader/efi_debug_support.c (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index eb61eafa028..6c4c1a0cc7b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -259,6 +259,22 @@ struct efi_capsule_result_variable_header { efi_status_t capsule_status; } __packed; +/** + * struct efi_system_table_pointer - struct to store the pointer of system + * table. + * @signature: The signature of this struct. + * @efi_system_table_base: The physical address of System Table. + * @crc32: CRC32 checksum + * + * This struct is design for hardware debugger to search through memory to + * get the address of EFI System Table. + */ +struct efi_system_table_pointer { + u64 signature; + efi_physical_addr_t efi_system_table_base; + u32 crc32; +}; + struct efi_memory_range { efi_physical_addr_t address; u64 length; diff --git a/include/efi_loader.h b/include/efi_loader.h index 8fd09aad2d0..ada29a5bad3 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -643,6 +643,8 @@ efi_status_t efi_tcg2_measure_dtb(void *dtb); efi_status_t efi_root_node_register(void); /* Called by bootefi to initialize runtime */ efi_status_t efi_initialize_system_table(void); +/* Called by bootefi to initialize debug */ +efi_status_t efi_initialize_system_table_pointer(void); /* efi_runtime_detach() - detach unimplemented runtime functions */ void efi_runtime_detach(void); /* efi_convert_pointer() - convert pointer to virtual address */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 3dadbc54b58..077466f01f0 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -71,6 +71,15 @@ config EFI_SECURE_BOOT config EFI_SIGNATURE_SUPPORT bool +config EFI_DEBUG_SUPPORT + bool "EFI Debug Support" + default y if !HAS_BOARD_SIZE_LIMIT + help + Select this option if you want to setup the EFI Debug Support + Table and the EFI_SYSTEM_TABLE_POINTER which is used by the debug + agent or an external debugger to determine loaded image information + in a quiescent manner. + menu "UEFI services" config EFI_GET_TIME diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index cf050e5385d..51ccf1cd87e 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o obj-$(CONFIG_EFI_SIGNATURE_SUPPORT) += efi_signature.o obj-$(CONFIG_EFI_ECPT) += efi_conformance.o +obj-$(CONFIG_EFI_DEBUG_SUPPORT) += efi_debug_support.o EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) diff --git a/lib/efi_loader/efi_debug_support.c b/lib/efi_loader/efi_debug_support.c new file mode 100644 index 00000000000..649d21ef829 --- /dev/null +++ b/lib/efi_loader/efi_debug_support.c @@ -0,0 +1,40 @@ +// 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; + +/** + * 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; +} diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 48f91da5df7..78c5059256a 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -278,6 +278,13 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; + /* Initialize system table pointer */ + if (IS_ENABLED(CONFIG_EFI_DEBUG_SUPPORT)) { + ret = efi_initialize_system_table_pointer(); + if (ret != EFI_SUCCESS) + goto out; + } + if (IS_ENABLED(CONFIG_EFI_ECPT)) { ret = efi_ecpt_register(); if (ret != EFI_SUCCESS) -- cgit v1.3.1 From e7a85ec651ed5794eb9a837e1073f6b3146af501 Mon Sep 17 00:00:00 2001 From: "Ying-Chun Liu (PaulLiu)" Date: Thu, 3 Jul 2025 07:28:08 +0100 Subject: efi: add EFI_DEBUG_IMAGE_INFO_TABLE for debug EFI_DEBUG_IMAGE_INFO_TABLE is used to store EFI_LOADED_IMAGE for debug purpose. This commit adds the table to the EFI_CONFIGURATION_TABLE. This feature is described in UEFI Spec version 2.10. Section 18.4. The implementation ensures support for hardware-assisted debugging and provides a standardized mechanism for debuggers to discover and interact with system-level debug resources. Cc: Heinrich Schuchardt Cc: Peter Robinson Cc: Simon Glass Signed-off-by: Ying-Chun Liu (PaulLiu) Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- include/efi_api.h | 53 ++++++++++++++++++++++++++++++++++++++ include/efi_loader.h | 2 ++ lib/efi_loader/efi_debug_support.c | 6 +++++ lib/efi_loader/efi_setup.c | 11 ++++++++ 4 files changed, 72 insertions(+) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 6c4c1a0cc7b..8da0a350ce3 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -238,6 +238,10 @@ enum efi_reset_type { EFI_GUID(0xcce33c35, 0x74ac, 0x4087, 0xbc, 0xe7, \ 0x8b, 0x29, 0xb0, 0x2e, 0xeb, 0x27) +#define EFI_DEBUG_IMAGE_INFO_TABLE_GUID \ + EFI_GUID(0x49152e77, 0x1ada, 0x4764, 0xb7, 0xa2, \ + 0x7a, 0xfe, 0xfe, 0xd9, 0x5e, 0x8b) + struct efi_conformance_profiles_table { u16 version; u16 number_of_profiles; @@ -574,6 +578,55 @@ struct efi_loaded_image { efi_status_t (EFIAPI *unload)(efi_handle_t image_handle); }; +#define EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS 0x01 +#define EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED 0x02 + +/** + * struct efi_debug_image_info_normal - Store Debug Information for normal + * image. + * @image_info_type: the type of image info. + * @loaded_image_protocol_instance: the pointer to struct efi_loaded_image. + * @image_handle: the EFI handle of the image. + * + * This struct is created by efi_load_image() and store the information + * for debugging an normal image. + */ +struct efi_debug_image_info_normal { + u32 image_info_type; + struct efi_loaded_image *loaded_image_protocol_instance; + efi_handle_t image_handle; +}; + +/** + * union efi_debug_image_info - The union to store a pointer for EFI + * DEBUG IMAGE INFO. + * @image_info_type: the type of the image_info if it is not a normal image. + * @normal_image: The pointer to a normal image. + * + * This union is for a pointer that can point to the struct of normal_image. + * Or it points to an image_info_type. + */ +union efi_debug_image_info { + u32 *image_info_type; + struct efi_debug_image_info_normal *normal_image; +}; + +/** + * struct efi_debug_image_info_table_header - store the array of + * struct efi_debug_image_info. + * @update_status: Status to notify this struct is ready to use or not. + * @table_size: The number of elements of efi_debug_image_info_table. + * @efi_debug_image_info_table: The array of efi_debug_image_info. + * + * This struct stores the array of efi_debug_image_info. The + * number of elements is table_size. + */ +struct efi_debug_image_info_table_header { + volatile u32 update_status; + u32 table_size; + union efi_debug_image_info *efi_debug_image_info_table; +}; + #define EFI_DEVICE_PATH_PROTOCOL_GUID \ EFI_GUID(0x09576e91, 0x6d3f, 0x11d2, \ 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) diff --git a/include/efi_loader.h b/include/efi_loader.h index ada29a5bad3..c02bc1b7ef4 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -312,6 +312,8 @@ extern const struct efi_hii_config_routing_protocol efi_hii_config_routing; extern const struct efi_hii_config_access_protocol efi_hii_config_access; extern const struct efi_hii_database_protocol efi_hii_database; extern const struct efi_hii_string_protocol efi_hii_string; +/* structure for EFI_DEBUG_SUPPORT_PROTOCOL */ +extern struct efi_debug_image_info_table_header efi_m_debug_info_table_header; uint16_t *efi_dp_str(struct efi_device_path *dp); diff --git a/lib/efi_loader/efi_debug_support.c b/lib/efi_loader/efi_debug_support.c index 649d21ef829..597592fbd1c 100644 --- a/lib/efi_loader/efi_debug_support.c +++ b/lib/efi_loader/efi_debug_support.c @@ -11,6 +11,12 @@ 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_initialize_system_table_pointer() - Initialize system table pointer * diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index 78c5059256a..f06cf49e443 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -18,6 +18,9 @@ efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED; +const efi_guid_t efi_debug_image_info_table_guid = + EFI_DEBUG_IMAGE_INFO_TABLE_GUID; + /* * Allow unaligned memory access. * @@ -280,9 +283,17 @@ efi_status_t efi_init_obj_list(void) /* Initialize system table pointer */ if (IS_ENABLED(CONFIG_EFI_DEBUG_SUPPORT)) { + efi_guid_t debug_image_info_table_guid = + efi_debug_image_info_table_guid; + ret = efi_initialize_system_table_pointer(); if (ret != EFI_SUCCESS) goto out; + + ret = efi_install_configuration_table(&debug_image_info_table_guid, + &efi_m_debug_info_table_header); + if (ret != EFI_SUCCESS) + goto out; } if (IS_ENABLED(CONFIG_EFI_ECPT)) { -- cgit v1.3.1 From 3c08df58cc43c3ae8ec378ab0e32cfe548313c39 Mon Sep 17 00:00:00 2001 From: "Ying-Chun Liu (PaulLiu)" Date: Thu, 3 Jul 2025 07:28:09 +0100 Subject: lib: efi_loader: efi_memory.c: add efi_realloc() for realloc memory Add efi_realloc() for realloc memory that previously alloc by efi_alloc(). Note that if realloced memory is explicitly allocated as BootServicesData. Cc: Heinrich Schuchardt Cc: Ilias Apalodimas Cc: Peter Robinson Cc: Simon Glass Signed-off-by: Ying-Chun Liu (PaulLiu) Reviewed-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- include/efi_loader.h | 10 ++++++++ lib/efi_loader/efi_memory.c | 58 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index c02bc1b7ef4..b60ea58d71f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -875,6 +875,16 @@ efi_status_t efi_next_variable_name(efi_uintn_t *size, u16 **buf, #define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) /* Allocate boot service data pool memory */ void *efi_alloc(size_t len); +/** + * efi_realloc() - reallocate boot services data pool memory + * + * Reallocate memory from pool for a new size and copy the data from old one. + * + * @ptr: pointer to the buffer + * @size: number of bytes to allocate + * Return: EFI status to indicate success or not + */ +efi_status_t efi_realloc(void **ptr, size_t len); /* Allocate pages on the specified alignment */ void *efi_alloc_aligned_pages(u64 len, int memory_type, size_t align); /* More specific EFI memory allocator, called by EFI payloads */ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 0828a47da61..6dfc698a247 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -668,6 +668,64 @@ void *efi_alloc(size_t size) return buf; } +/** + * efi_realloc() - reallocate boot services data pool memory + * + * Reallocate memory from pool for a new size and copy the data from old one. + * + * @ptr: pointer to old buffer + * @size: number of bytes to allocate + * Return: EFI status to indicate success or not + */ +efi_status_t efi_realloc(void **ptr, size_t size) +{ + efi_status_t ret; + void *new_ptr; + struct efi_pool_allocation *alloc; + u64 num_pages = efi_size_in_pages(size + + sizeof(struct efi_pool_allocation)); + size_t old_size; + + if (!*ptr) { + *ptr = efi_alloc(size); + if (*ptr) + return EFI_SUCCESS; + return EFI_OUT_OF_RESOURCES; + } + + ret = efi_check_allocated((uintptr_t)*ptr, true); + if (ret != EFI_SUCCESS) + return ret; + + alloc = container_of(*ptr, struct efi_pool_allocation, data); + + /* Check that this memory was allocated by efi_allocate_pool() */ + if (((uintptr_t)alloc & EFI_PAGE_MASK) || + alloc->checksum != checksum(alloc)) { + printf("%s: illegal realloc 0x%p\n", __func__, *ptr); + return EFI_INVALID_PARAMETER; + } + + /* Don't realloc. The actual size in pages is the same. */ + if (alloc->num_pages == num_pages) + return EFI_SUCCESS; + + old_size = alloc->num_pages * EFI_PAGE_SIZE - + sizeof(struct efi_pool_allocation); + + new_ptr = efi_alloc(size); + + /* copy old data to new alloced buffer */ + memcpy(new_ptr, *ptr, min(size, old_size)); + + /* free the old buffer */ + efi_free_pool(*ptr); + + *ptr = new_ptr; + + return EFI_SUCCESS; +} + /** * efi_free_pool() - free memory from pool * -- cgit v1.3.1 From 146546138af5966c97619797dc7f879c4857b00d Mon Sep 17 00:00:00 2001 From: "Ying-Chun Liu (PaulLiu)" Date: Thu, 3 Jul 2025 07:28:10 +0100 Subject: efi: add EFI_DEBUG_IMAGE_INFO for debug This commit adds the functionality of generate EFI_DEBUG_IMAGE_INFO while loading the image. This feature is described in UEFI Spec 2.10. Section 18.4.3. The implementation ensures support for hardware-assisted debugging and provides a standardized mechanism for debuggers to discover the load address of an EFI application. Cc: Ilias Apalodimas Cc: Peter Robinson Cc: Simon Glass Signed-off-by: Ying-Chun Liu (PaulLiu) Tested-by: Heinrich Schuchardt Acked-by: Ilias Apalodimas Signed-off-by: Ilias Apalodimas --- include/efi_api.h | 2 + include/efi_loader.h | 5 ++ lib/efi_loader/efi_boottime.c | 7 ++ lib/efi_loader/efi_debug_support.c | 137 +++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 8da0a350ce3..77a05f752e5 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -581,6 +581,8 @@ struct efi_loaded_image { #define EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS 0x01 #define EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED 0x02 +#define EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL 0x01 + /** * struct efi_debug_image_info_normal - Store Debug Information for normal * image. diff --git a/include/efi_loader.h b/include/efi_loader.h index b60ea58d71f..3e70ac07055 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -647,6 +647,11 @@ efi_status_t efi_root_node_register(void); efi_status_t efi_initialize_system_table(void); /* Called by bootefi to initialize debug */ efi_status_t efi_initialize_system_table_pointer(void); +/* Called by efi_load_image for register debug info */ +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); +void efi_core_remove_debug_image_info_entry(efi_handle_t image_handle); /* efi_runtime_detach() - detach unimplemented runtime functions */ void efi_runtime_detach(void); /* efi_convert_pointer() - convert pointer to virtual address */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 754bc6a6519..ddc935d2240 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2130,6 +2130,11 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy, *image_handle = NULL; free(info); } + + if (IS_ENABLED(CONFIG_EFI_DEBUG_SUPPORT) && *image_handle) + efi_core_new_debug_image_info_entry(EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, + info, + *image_handle); error: return EFI_EXIT(ret); } @@ -3360,6 +3365,8 @@ efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) ret = EFI_INVALID_PARAMETER; goto out; } + if (IS_ENABLED(CONFIG_EFI_DEBUG_SUPPORT)) + efi_core_remove_debug_image_info_entry(image_handle); switch (efiobj->type) { case EFI_OBJECT_TYPE_STARTED_IMAGE: /* Call the unload function */ diff --git a/lib/efi_loader/efi_debug_support.c b/lib/efi_loader/efi_debug_support.c index 597592fbd1c..186bdbce750 100644 --- a/lib/efi_loader/efi_debug_support.c +++ b/lib/efi_loader/efi_debug_support.c @@ -17,6 +17,13 @@ struct efi_debug_image_info_table_header efi_m_debug_info_table_header = { 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 * @@ -44,3 +51,133 @@ efi_status_t efi_initialize_system_table_pointer(void) 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; +} -- cgit v1.3.1