summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/eficonfig.c146
-rw-r--r--disk/part_efi.c67
-rw-r--r--include/efi_api.h71
-rw-r--r--include/efi_config.h2
-rw-r--r--include/efi_loader.h19
-rw-r--r--include/part.h14
-rw-r--r--include/part_efi.h20
-rw-r--r--lib/efi_loader/Kconfig9
-rw-r--r--lib/efi_loader/Makefile2
-rw-r--r--lib/efi_loader/dbginfodump.c356
-rw-r--r--lib/efi_loader/efi_boottime.c7
-rw-r--r--lib/efi_loader/efi_debug_support.c183
-rw-r--r--lib/efi_loader/efi_disk.c39
-rw-r--r--lib/efi_loader/efi_file.c2
-rw-r--r--lib/efi_loader/efi_http.c9
-rw-r--r--lib/efi_loader/efi_memory.c58
-rw-r--r--lib/efi_loader/efi_net.c2
-rw-r--r--lib/efi_loader/efi_setup.c18
-rw-r--r--lib/efi_selftest/Makefile2
-rw-r--r--lib/efi_selftest/efi_selftest_block_device.c30
-rw-r--r--lib/efi_selftest/efi_selftest_debug_support.c40
-rw-r--r--test/cmd/wget.c20
22 files changed, 1072 insertions, 44 deletions
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
@@ -539,6 +540,40 @@ struct efi_device_path *eficonfig_create_device_path(struct efi_device_path *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
*
* @data: pointer to the data of selected entry
@@ -984,6 +1019,22 @@ static efi_status_t eficonfig_boot_add_optional_data(void *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
*
* @data: pointer to the internal boot option structure
@@ -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;
@@ -1341,6 +1431,27 @@ out:
}
/**
+ * 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
*
* @dp: pointer to the device path
@@ -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/disk/part_efi.c b/disk/part_efi.c
index 68ba1d11e7b..fb1ed534f86 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -215,6 +215,34 @@ int get_disk_guid(struct blk_desc *desc, char *guid)
return 0;
}
+int part_get_gpt_pte(struct blk_desc *desc, int part, gpt_entry *gpt_e)
+{
+ ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, desc->blksz);
+ gpt_entry *gpt_pte = NULL;
+
+ /* "part" argument must be at least 1 */
+ if (part < 1) {
+ log_debug("Invalid Argument(s)\n");
+ return -EINVAL;
+ }
+
+ /* This function validates AND fills in the GPT header and PTE */
+ if (find_valid_gpt(desc, gpt_head, &gpt_pte) != 1)
+ return -EINVAL;
+
+ if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
+ !is_pte_valid(&gpt_pte[part - 1])) {
+ log_debug("Invalid partition number %d\n", part);
+ free(gpt_pte);
+ return -EPERM;
+ }
+
+ memcpy(gpt_e, &gpt_pte[part - 1], sizeof(*gpt_e));
+
+ free(gpt_pte);
+ return 0;
+}
+
static void __maybe_unused part_print_efi(struct blk_desc *desc)
{
ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, desc->blksz);
@@ -260,45 +288,32 @@ static void __maybe_unused part_print_efi(struct blk_desc *desc)
static int __maybe_unused part_get_info_efi(struct blk_desc *desc, int part,
struct disk_partition *info)
{
- ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, desc->blksz);
- gpt_entry *gpt_pte = NULL;
-
- /* "part" argument must be at least 1 */
- if (part < 1) {
- log_debug("Invalid Argument(s)\n");
- return -EINVAL;
- }
-
- /* This function validates AND fills in the GPT header and PTE */
- if (find_valid_gpt(desc, gpt_head, &gpt_pte) != 1)
- return -EINVAL;
+ gpt_entry gpt_pte = {};
+ int ret;
- if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
- !is_pte_valid(&gpt_pte[part - 1])) {
- log_debug("Invalid partition number %d\n", part);
- free(gpt_pte);
- return -EPERM;
- }
+ ret = part_get_gpt_pte(desc, part, &gpt_pte);
+ if (ret)
+ return ret;
/* The 'lbaint_t' casting may limit the maximum disk size to 2 TB */
- info->start = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].starting_lba);
+ info->start = (lbaint_t)le64_to_cpu(gpt_pte.starting_lba);
/* The ending LBA is inclusive, to calculate size, add 1 to it */
- info->size = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1
+ info->size = (lbaint_t)le64_to_cpu(gpt_pte.ending_lba) + 1
- info->start;
info->blksz = desc->blksz;
snprintf((char *)info->name, sizeof(info->name), "%s",
- print_efiname(&gpt_pte[part - 1]));
+ print_efiname(&gpt_pte));
strcpy((char *)info->type, "U-Boot");
- info->bootable = get_bootable(&gpt_pte[part - 1]);
- info->type_flags = gpt_pte[part - 1].attributes.fields.type_guid_specific;
+ info->bootable = get_bootable(&gpt_pte);
+ info->type_flags = gpt_pte.attributes.fields.type_guid_specific;
if (CONFIG_IS_ENABLED(PARTITION_UUIDS)) {
- uuid_bin_to_str(gpt_pte[part - 1].unique_partition_guid.b,
+ uuid_bin_to_str(gpt_pte.unique_partition_guid.b,
(char *)disk_partition_uuid(info),
UUID_STR_FORMAT_GUID);
}
if (IS_ENABLED(CONFIG_PARTITION_TYPE_GUID)) {
- uuid_bin_to_str(gpt_pte[part - 1].partition_type_guid.b,
+ uuid_bin_to_str(gpt_pte.partition_type_guid.b,
(char *)disk_partition_type_guid(info),
UUID_STR_FORMAT_GUID);
}
@@ -306,8 +321,6 @@ static int __maybe_unused part_get_info_efi(struct blk_desc *desc, int part,
log_debug("start 0x" LBAF ", size 0x" LBAF ", name %s\n", info->start,
info->size, info->name);
- /* Remember to free pte */
- free(gpt_pte);
return 0;
}
diff --git a/include/efi_api.h b/include/efi_api.h
index eb61eafa028..77a05f752e5 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;
@@ -259,6 +263,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;
@@ -558,6 +578,57 @@ 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
+
+#define EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL 0x01
+
+/**
+ * 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_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;
};
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 8fd09aad2d0..3e70ac07055 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);
@@ -643,6 +645,13 @@ 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);
+/* 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 */
@@ -871,6 +880,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/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)
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/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..bfa607c8827 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -21,6 +21,7 @@ ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
apps-y += dtbdump
endif
apps-$(CONFIG_BOOTEFI_TESTAPP_COMPILE) += testapp
+apps-y += dbginfodump
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
obj-$(CONFIG_EFI_BOOTMGR) += efi_bootmgr.o
@@ -70,6 +71,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/dbginfodump.c b/lib/efi_loader/dbginfodump.c
new file mode 100644
index 00000000000..adbbd5060cc
--- /dev/null
+++ b/lib/efi_loader/dbginfodump.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2025, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * dbginfodump.efi prints out the content of the EFI_DEBUG_IMAGE_INFO_TABLE.
+ */
+
+#include <efi_api.h>
+
+/**
+ * BUFFER_SIZE - size of the command line input buffer
+ */
+#define BUFFER_SIZE 64
+
+static struct efi_simple_text_output_protocol *cerr;
+static struct efi_simple_text_output_protocol *cout;
+static struct efi_simple_text_input_protocol *cin;
+static efi_handle_t handle;
+static struct efi_system_table *systable;
+static struct efi_boot_services *bs;
+
+static efi_guid_t guid_device_path_to_text_protocol =
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
+
+static struct efi_device_path_to_text_protocol *device_path_to_text;
+
+/* EFI_DEBUG_IMAGE_INFO_TABLE_GUID */
+static const efi_guid_t dbg_info_guid =
+ EFI_GUID(0x49152E77, 0x1ADA, 0x4764, 0xB7, 0xA2,
+ 0x7A, 0xFE, 0xFE, 0xD9, 0x5E, 0x8B);
+
+/* EFI_DEBUG_IMAGE_INFO_NORMAL */
+struct dbg_info {
+ u32 type;
+ struct efi_loaded_image *info;
+ efi_handle_t handle;
+};
+
+/* FI_DEBUG_IMAGE_INFO_TABLE_HEADER */
+struct dbg_info_header {
+ u32 status;
+ u32 size;
+ struct dbg_info **info;
+};
+
+/**
+ * print() - print string
+ *
+ * @string: text
+ */
+static void print(u16 *string)
+{
+ cout->output_string(cout, string);
+}
+
+/**
+ * error() - print error string
+ *
+ * @string: error text
+ */
+static void error(u16 *string)
+{
+ cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
+ print(string);
+ cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+}
+
+/**
+ * printu() - print unsigned
+ *
+ * @val: value to print
+ */
+static void printu(u32 val)
+{
+ u16 str[19] = u"0x";
+ u16 *ptr = &str[2];
+ u16 ch;
+
+ for (ssize_t i = 8 * sizeof(u32) - 4; i >= 0; i -= 4) {
+ ch = (val >> i & 0xf) + '0';
+ if (ch > '9')
+ ch += 'a' - '9' - 1;
+ *ptr++ = ch;
+ }
+ *ptr = 0;
+ print(str);
+}
+
+/**
+ * printp() - print pointer
+ *
+ * @p: pointer
+ */
+static void printp(void *p)
+{
+ u16 str[19] = u"0x";
+ u16 *ptr = &str[2];
+ u16 ch;
+
+ for (ssize_t i = 8 * sizeof(void *) - 4; i >= 0; i -= 4) {
+ ch = ((uintptr_t)p >> i & 0xf) + '0';
+ if (ch > '9')
+ ch += 'a' - '9' - 1;
+ *ptr++ = ch;
+ }
+ *ptr = 0;
+ print(str);
+}
+
+/**
+ * efi_input() - read string from console
+ *
+ * @buffer: input buffer
+ * @buffer_size: buffer size
+ * Return: status code
+ */
+static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
+{
+ struct efi_input_key key = {0};
+ efi_uintn_t index;
+ efi_uintn_t pos = 0;
+ u16 outbuf[2] = u" ";
+ efi_status_t ret;
+
+ /* Drain the console input */
+ ret = cin->reset(cin, true);
+ *buffer = 0;
+ for (;;) {
+ ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
+ if (ret != EFI_SUCCESS)
+ continue;
+ ret = cin->read_key_stroke(cin, &key);
+ if (ret != EFI_SUCCESS)
+ continue;
+ switch (key.scan_code) {
+ case 0x17: /* Escape */
+ print(u"\r\nAborted\r\n");
+ return EFI_ABORTED;
+ default:
+ break;
+ }
+ switch (key.unicode_char) {
+ case 0x08: /* Backspace */
+ if (pos) {
+ buffer[pos--] = 0;
+ print(u"\b \b");
+ }
+ break;
+ case 0x0a: /* Linefeed */
+ case 0x0d: /* Carriage return */
+ print(u"\r\n");
+ return EFI_SUCCESS;
+ default:
+ break;
+ }
+ /* Ignore surrogate codes */
+ if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
+ continue;
+ if (key.unicode_char >= 0x20 &&
+ pos < buffer_size - 1) {
+ *outbuf = key.unicode_char;
+ buffer[pos++] = key.unicode_char;
+ buffer[pos] = 0;
+ print(outbuf);
+ }
+ }
+}
+
+/**
+ * skip_whitespace() - skip over leading whitespace
+ *
+ * @pos: UTF-16 string
+ * Return: pointer to first non-whitespace
+ */
+static u16 *skip_whitespace(u16 *pos)
+{
+ for (; *pos && *pos <= 0x20; ++pos)
+ ;
+ return pos;
+}
+
+/**
+ * starts_with() - check if @string starts with @keyword
+ *
+ * @string: string to search for keyword
+ * @keyword: keyword to be searched
+ * Return: true fi @string starts with the keyword
+ */
+static bool starts_with(u16 *string, u16 *keyword)
+{
+ for (; *keyword; ++string, ++keyword) {
+ if (*string != *keyword)
+ return false;
+ }
+ return true;
+}
+
+/**
+ * do_help() - print help
+ */
+static void do_help(void)
+{
+ error(u"dump - print debug info table\r\n");
+ error(u"exit - exit the shell\r\n");
+}
+
+/**
+ * get_dbg_info_table() - get debug info table
+ *
+ * Return: debug info table or NULL
+ */
+static void *get_dbg_info(void)
+{
+ void *dbg = NULL;
+ efi_uintn_t i;
+
+ for (i = 0; i < systable->nr_tables; ++i) {
+ if (!memcmp(&systable->tables[i].guid, &dbg_info_guid,
+ sizeof(efi_guid_t))) {
+ dbg = systable->tables[i].table;
+ break;
+ }
+ }
+ return dbg;
+}
+
+/**
+ * print_info() - print loaded image protocol
+ */
+static void print_info(struct efi_loaded_image *info)
+{
+ print(u" Address: [");
+ printp(info->image_base);
+ print(u", ");
+ printp(info->image_base + info->image_size - 1);
+ print(u"]\r\n");
+ if (device_path_to_text && info->file_path) {
+ u16 *string;
+
+ string = device_path_to_text->convert_device_path_to_text(
+ info->file_path, true, false);
+ if (!string) {
+ error(u"ConvertDevicePathToText failed");
+ } else {
+ print(u" File: ");
+ print(string);
+ }
+ print(u"\r\n");
+ }
+}
+
+/**
+ * do_dump() - print debug info table
+ */
+static efi_status_t do_dump(void)
+{
+ struct dbg_info_header *dbg;
+ u32 count;
+
+ dbg = get_dbg_info();
+ if (!dbg) {
+ error(u"Debug info table not found\r\n");
+ return EFI_NOT_FOUND;
+ }
+ if (dbg->status & 0x01) {
+ error(u"Update in progress\r\n");
+ return EFI_LOAD_ERROR;
+ }
+ if (dbg->status & 0x02)
+ print(u"Modified\r\n");
+ print(u"Number of entries: ");
+ printu(dbg->size);
+ print(u"\r\n");
+
+ count = dbg->size;
+ for (u32 i = 0; count; ++i) {
+ struct dbg_info *info = dbg->info[i];
+
+ /*
+ * The EDK II implementation decreases the size field and
+ * writes a NULL value when deleting an entry which is not
+ * backed by the UEFI specification.
+ */
+ if (!info) {
+ print(u"Deleted entry\r\n");
+ continue;
+ }
+ --count;
+ print(u"Info type ");
+ printu(info->type);
+ print(u"\r\n");
+ if (info->type != 1)
+ continue;
+ print_info(info->info);
+ print(u" Handle: ");
+ printp(info->handle);
+ print(u"\r\n");
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * efi_main() - entry point of the EFI application.
+ *
+ * @handle: handle of the loaded image
+ * @systab: system table
+ * Return: status code
+ */
+efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
+ struct efi_system_table *systab)
+{
+ efi_status_t ret;
+
+ handle = image_handle;
+ systable = systab;
+ cerr = systable->std_err;
+ cout = systable->con_out;
+ cin = systable->con_in;
+ bs = systable->boottime;
+
+ cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+ cout->clear_screen(cout);
+ cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
+ print(u"Debug Info Table Dump\r\n=====================\r\n\r\n");
+ cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
+
+ ret = bs->locate_protocol(&guid_device_path_to_text_protocol,
+ NULL, (void **)&device_path_to_text);
+ if (ret != EFI_SUCCESS) {
+ error(u"No device path to text protocol\r\n");
+ device_path_to_text = NULL;
+ }
+
+ for (;;) {
+ u16 command[BUFFER_SIZE];
+ u16 *pos;
+ efi_uintn_t ret;
+
+ print(u"=> ");
+ ret = efi_input(command, sizeof(command));
+ if (ret == EFI_ABORTED)
+ break;
+ pos = skip_whitespace(command);
+ if (starts_with(pos, u"exit"))
+ break;
+ else if (starts_with(pos, u"dump"))
+ do_dump();
+ else
+ do_help();
+ }
+
+ cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
+ cout->clear_screen(cout);
+ return EFI_SUCCESS;
+}
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
new file mode 100644
index 00000000000..186bdbce750
--- /dev/null
+++ b/lib/efi_loader/efi_debug_support.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * EFI debug support
+ *
+ * Copyright (c) 2025 Ying-Chun Liu, Linaro Ltd. <paul.liu@linaro.org>
+ */
+
+#include <efi_loader.h>
+#include <linux/sizes.h>
+#include <u-boot/crc.h>
+
+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;
+}
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.
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 7d81da8f2d8..19b43c4a625 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -248,7 +248,7 @@ static struct efi_file_handle *file_open(struct file_system *fs,
return &fh->base;
error:
- free(fh->path);
+ free(path);
free(fh);
return NULL;
}
diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c
index 189317fe2d2..9a0f2675132 100644
--- a/lib/efi_loader/efi_http.c
+++ b/lib/efi_loader/efi_http.c
@@ -453,7 +453,6 @@ static efi_status_t EFIAPI efi_http_service_binding_destroy_child(
efi_status_t ret = EFI_SUCCESS;
struct efi_http_instance *http_instance;
struct efi_handler *phandler;
- void *protocol_interface;
if (num_instances == 0)
return EFI_EXIT(EFI_NOT_FOUND);
@@ -463,18 +462,18 @@ static efi_status_t EFIAPI efi_http_service_binding_destroy_child(
efi_search_protocol(child_handle, &efi_http_guid, &phandler);
- if (phandler)
- protocol_interface = phandler->protocol_interface;
+ if (!phandler)
+ return EFI_EXIT(EFI_UNSUPPORTED);
ret = efi_delete_handle(child_handle);
if (ret != EFI_SUCCESS)
return EFI_EXIT(ret);
- http_instance = (struct efi_http_instance *)protocol_interface;
+ http_instance = phandler->protocol_interface;
efi_free_pool(http_instance->http_load_addr);
http_instance->http_load_addr = NULL;
- free(protocol_interface);
+ free(phandler->protocol_interface);
num_instances--;
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
@@ -669,6 +669,64 @@ void *efi_alloc(size_t size)
}
/**
+ * 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
*
* @buffer: start of memory to be freed
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 86f0af9538c..b8a6e08ba8e 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -1131,7 +1131,7 @@ efi_status_t efi_net_register(struct udevice *dev)
struct efi_net_obj *netobj;
void *transmit_buffer = NULL;
uchar **receive_buffer = NULL;
- size_t *receive_lengths;
+ size_t *receive_lengths = NULL;
int i, j;
if (!dev) {
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index 48f91da5df7..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.
*
@@ -278,6 +281,21 @@ 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)) {
+ 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)) {
ret = efi_ecpt_register();
if (ret != EFI_SUCCESS)
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index d78bf7d6191..842433f68aa 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -78,6 +78,8 @@ endif
obj-$(CONFIG_EFI_ESRT) += efi_selftest_esrt.o
+obj-$(CONFIG_EFI_DEBUG_SUPPORT) += efi_selftest_debug_support.o
+
targets += \
efi_miniapp_file_image_exception.h \
efi_miniapp_file_image_exit.h \
diff --git a/lib/efi_selftest/efi_selftest_block_device.c b/lib/efi_selftest/efi_selftest_block_device.c
index a367e8b89d1..f145e58a267 100644
--- a/lib/efi_selftest/efi_selftest_block_device.c
+++ b/lib/efi_selftest/efi_selftest_block_device.c
@@ -18,6 +18,7 @@
#include <efi_selftest.h>
#include "efi_selftest_disk_image.h"
#include <asm/cache.h>
+#include <part_efi.h>
/* Block size of compressed disk image */
#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
@@ -29,6 +30,7 @@ static struct efi_boot_services *boottime;
static const efi_guid_t block_io_protocol_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
static const efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
+static const efi_guid_t partition_info_guid = EFI_PARTITION_INFO_PROTOCOL_GUID;
static const efi_guid_t guid_simple_file_system_protocol =
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID;
@@ -310,6 +312,7 @@ static int execute(void)
struct efi_file_system_info info;
u16 label[12];
} system_info;
+ struct efi_partition_info *part_info;
efi_uintn_t buf_size;
char buf[16] __aligned(ARCH_DMA_MINALIGN);
u32 part1_size;
@@ -375,6 +378,33 @@ static int execute(void)
part1_size - 1);
return EFI_ST_FAILURE;
}
+
+ /* Open the partition information protocol */
+ ret = boottime->open_protocol(handle_partition,
+ &partition_info_guid,
+ (void **)&part_info, NULL, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to open partition information protocol\n");
+ return EFI_ST_FAILURE;
+ }
+ /* Check that cached partition information is the expected */
+ if (part_info->revision != EFI_PARTITION_INFO_PROTOCOL_REVISION) {
+ efi_st_error("Partition info revision %x, expected %x\n",
+ part_info->revision, EFI_PARTITION_INFO_PROTOCOL_REVISION);
+ return EFI_ST_FAILURE;
+ }
+ if (part_info->type != PARTITION_TYPE_MBR) {
+ efi_st_error("Partition info type %x, expected %x\n",
+ part_info->type, PARTITION_TYPE_MBR);
+ return EFI_ST_FAILURE;
+ }
+ if (part_info->system != 0) {
+ efi_st_error("Partition info system %x, expected 0\n",
+ part_info->system);
+ return EFI_ST_FAILURE;
+ }
+
/* Open the simple file system protocol */
ret = boottime->open_protocol(handle_partition,
&guid_simple_file_system_protocol,
diff --git a/lib/efi_selftest/efi_selftest_debug_support.c b/lib/efi_selftest/efi_selftest_debug_support.c
new file mode 100644
index 00000000000..9ca8b3f82f5
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_debug_support.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * efi_selftest_debug_support
+ *
+ * Copyright (c) 2025 Ying-Chun Liu, Linaro Ltd. <paul.liu@linaro.org>
+ *
+ * Test the EFI_DEBUG_SUPPORT
+ */
+
+#include <efi_loader.h>
+#include <efi_selftest.h>
+
+/**
+ * efi_st_debug_support_execute() - execute test
+ *
+ * Test EFI_DEBUG_SUPPORT tables.
+ *
+ * Return: status code
+ */
+static int efi_st_debug_support_execute(void)
+{
+ struct efi_debug_image_info_table_header *efi_st_debug_info_table_header = NULL;
+ efi_guid_t efi_debug_image_info_table_guid = EFI_DEBUG_IMAGE_INFO_TABLE_GUID;
+
+ /* get EFI_DEBUG_IMAGE_INFO_TABLE */
+ efi_st_debug_info_table_header = efi_st_get_config_table(&efi_debug_image_info_table_guid);
+
+ if (!efi_st_debug_info_table_header) {
+ efi_st_error("Missing EFI_DEBUG_IMAGE_INFO_TABLE\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(debug_support) = {
+ .name = "debug_support",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .execute = efi_st_debug_support_execute,
+};
diff --git a/test/cmd/wget.c b/test/cmd/wget.c
index 445750660c2..1005392b952 100644
--- a/test/cmd/wget.c
+++ b/test/cmd/wget.c
@@ -241,3 +241,23 @@ static int net_test_wget(struct unit_test_state *uts)
return 0;
}
CMD_TEST(net_test_wget, UTF_CONSOLE);
+
+static int net_test_wget_uri_validate(struct unit_test_state *uts)
+{
+ ut_asserteq(true, wget_validate_uri("http://foo.com/bar.html"));
+ ut_asserteq(true, wget_validate_uri("http://1.1.2.3/bar.html"));
+ ut_asserteq(false, wget_validate_uri("http://foo/ba r.html"));
+ ut_asserteq(false, wget_validate_uri("http://"));
+
+ if (CONFIG_IS_ENABLED(WGET_HTTPS)) {
+ ut_asserteq(true,
+ wget_validate_uri("https://foo.com/bar.html"));
+ ut_asserteq(true,
+ wget_validate_uri("https://1.1.2.3/bar.html"));
+ ut_asserteq(false, wget_validate_uri("https://foo/ba r.html"));
+ ut_asserteq(false, wget_validate_uri("https://"));
+ }
+
+ return 0;
+}
+CMD_TEST(net_test_wget_uri_validate, UTF_CONSOLE);