diff options
-rw-r--r-- | cmd/eficonfig.c | 146 | ||||
-rw-r--r-- | disk/part_efi.c | 67 | ||||
-rw-r--r-- | include/efi_api.h | 71 | ||||
-rw-r--r-- | include/efi_config.h | 2 | ||||
-rw-r--r-- | include/efi_loader.h | 19 | ||||
-rw-r--r-- | include/part.h | 14 | ||||
-rw-r--r-- | include/part_efi.h | 20 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 9 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 2 | ||||
-rw-r--r-- | lib/efi_loader/dbginfodump.c | 356 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 7 | ||||
-rw-r--r-- | lib/efi_loader/efi_debug_support.c | 183 | ||||
-rw-r--r-- | lib/efi_loader/efi_disk.c | 39 | ||||
-rw-r--r-- | lib/efi_loader/efi_file.c | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_http.c | 9 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 58 | ||||
-rw-r--r-- | lib/efi_loader/efi_net.c | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_setup.c | 18 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 2 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_block_device.c | 30 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_debug_support.c | 40 | ||||
-rw-r--r-- | test/cmd/wget.c | 20 |
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); |