diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 2 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 271 | ||||
-rw-r--r-- | lib/efi_loader/efi_disk.c | 20 | ||||
-rw-r--r-- | lib/efi_loader/efi_hii_config.c | 10 | ||||
-rw-r--r-- | lib/efi_loader/efi_load_initrd.c | 3 | ||||
-rw-r--r-- | lib/efi_loader/efi_root_node.c | 3 | ||||
-rw-r--r-- | lib/efi_loader/efi_runtime.c | 4 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 17 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_load_file.c | 475 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_load_initrd.c | 7 |
11 files changed, 692 insertions, 122 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index 7673d2e4e04..06eb8d07dcf 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -168,7 +168,7 @@ config REGEX choice prompt "Pseudo-random library support type" depends on NET_RANDOM_ETHADDR || RANDOM_UUID || CMD_UUID || \ - RNG_SANDBOX || UT_LIB && AES + RNG_SANDBOX || UT_LIB && AES || FAT_WRITE default LIB_RAND help Select the library to provide pseudo-random number generator diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 0afcaf48132..462d4d9ac45 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -30,7 +30,7 @@ obj-y += efi_device_path.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o obj-y += efi_device_path_utilities.o obj-y += efi_file.o -obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o +obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o obj-y += efi_image_loader.o obj-y += efi_memory.o obj-y += efi_root_node.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 246b59d3b35..03053e8660d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -81,6 +81,9 @@ const efi_guid_t efi_guid_event_group_ready_to_boot = /* event group ResetSystem() invoked (before ExitBootServices) */ const efi_guid_t efi_guid_event_group_reset_system = EFI_EVENT_GROUP_RESET_SYSTEM; +/* GUIDs of the Load File and Load File2 protocols */ +const efi_guid_t efi_guid_load_file_protocol = EFI_LOAD_FILE_PROTOCOL_GUID; +const efi_guid_t efi_guid_load_file2_protocol = EFI_LOAD_FILE2_PROTOCOL_GUID; static efi_status_t EFIAPI efi_disconnect_controller( efi_handle_t controller_handle, @@ -1770,30 +1773,108 @@ failure: } /** - * efi_load_image_from_path() - load an image using a file path + * efi_locate_device_path() - Get the device path and handle of an device + * implementing a protocol + * @protocol: GUID of the protocol + * @device_path: device path + * @device: handle of the device + * + * This function implements the LocateDevicePath service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +static efi_status_t EFIAPI efi_locate_device_path( + const efi_guid_t *protocol, + struct efi_device_path **device_path, + efi_handle_t *device) +{ + struct efi_device_path *dp; + size_t i; + struct efi_handler *handler; + efi_handle_t *handles; + size_t len, len_dp; + size_t len_best = 0; + efi_uintn_t no_handles; + u8 *remainder; + efi_status_t ret; + + EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); + + if (!protocol || !device_path || !*device_path) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* Find end of device path */ + len = efi_dp_instance_size(*device_path); + + /* Get all handles implementing the protocol */ + ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL, + &no_handles, &handles)); + if (ret != EFI_SUCCESS) + goto out; + + for (i = 0; i < no_handles; ++i) { + /* Find the device path protocol */ + ret = efi_search_protocol(handles[i], &efi_guid_device_path, + &handler); + if (ret != EFI_SUCCESS) + continue; + dp = (struct efi_device_path *)handler->protocol_interface; + len_dp = efi_dp_instance_size(dp); + /* + * This handle can only be a better fit + * if its device path length is longer than the best fit and + * if its device path length is shorter of equal the searched + * device path. + */ + if (len_dp <= len_best || len_dp > len) + continue; + /* Check if dp is a subpath of device_path */ + if (memcmp(*device_path, dp, len_dp)) + continue; + if (!device) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + *device = handles[i]; + len_best = len_dp; + } + if (len_best) { + remainder = (u8 *)*device_path + len_best; + *device_path = (struct efi_device_path *)remainder; + ret = EFI_SUCCESS; + } else { + ret = EFI_NOT_FOUND; + } +out: + return EFI_EXIT(ret); +} + +/** + * efi_load_image_from_file() - load an image from file system * * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the * callers obligation to update the memory type as needed. * - * @file_path: the path of the image to load - * @buffer: buffer containing the loaded image - * @size: size of the loaded image - * Return: status code + * @file_path: the path of the image to load + * @buffer: buffer containing the loaded image + * @size: size of the loaded image + * Return: status code */ static -efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, +efi_status_t efi_load_image_from_file(struct efi_device_path *file_path, void **buffer, efi_uintn_t *size) { struct efi_file_info *info = NULL; struct efi_file_handle *f; - static efi_status_t ret; + efi_status_t ret; u64 addr; efi_uintn_t bs; - /* In case of failure nothing is returned */ - *buffer = NULL; - *size = 0; - /* Open file */ f = efi_file_from_path(file_path); if (!f) @@ -1842,6 +1923,86 @@ error: } /** + * efi_load_image_from_path() - load an image using a file path + * + * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the + * callers obligation to update the memory type as needed. + * + * @boot_policy: true for request originating from the boot manager + * @file_path: the path of the image to load + * @buffer: buffer containing the loaded image + * @size: size of the loaded image + * Return: status code + */ +static +efi_status_t efi_load_image_from_path(bool boot_policy, + struct efi_device_path *file_path, + void **buffer, efi_uintn_t *size) +{ + efi_handle_t device; + efi_status_t ret; + struct efi_device_path *dp; + struct efi_load_file_protocol *load_file_protocol = NULL; + efi_uintn_t buffer_size; + uint64_t addr, pages; + const efi_guid_t *guid; + + /* In case of failure nothing is returned */ + *buffer = NULL; + *size = 0; + + dp = file_path; + ret = EFI_CALL(efi_locate_device_path( + &efi_simple_file_system_protocol_guid, &dp, &device)); + if (ret == EFI_SUCCESS) + return efi_load_image_from_file(file_path, buffer, size); + + ret = EFI_CALL(efi_locate_device_path( + &efi_guid_load_file_protocol, &dp, &device)); + if (ret == EFI_SUCCESS) { + guid = &efi_guid_load_file_protocol; + } else if (!boot_policy) { + guid = &efi_guid_load_file2_protocol; + ret = EFI_CALL(efi_locate_device_path(guid, &dp, &device)); + } + if (ret != EFI_SUCCESS) + return EFI_NOT_FOUND; + ret = EFI_CALL(efi_handle_protocol(device, guid, + (void **)&load_file_protocol)); + if (ret != EFI_SUCCESS) + return EFI_NOT_FOUND; + buffer_size = 0; + ret = load_file_protocol->load_file(load_file_protocol, dp, + boot_policy, &buffer_size, + NULL); + if (ret != EFI_BUFFER_TOO_SMALL) + goto out; + pages = efi_size_in_pages(buffer_size); + ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_BOOT_SERVICES_DATA, + pages, &addr); + if (ret != EFI_SUCCESS) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + ret = EFI_CALL(load_file_protocol->load_file( + load_file_protocol, dp, boot_policy, + &buffer_size, (void *)(uintptr_t)addr)); + if (ret != EFI_SUCCESS) + efi_free_pages(addr, pages); +out: + if (load_file_protocol) + EFI_CALL(efi_close_protocol(device, + &efi_guid_load_file2_protocol, + efi_root, NULL)); + if (ret == EFI_SUCCESS) { + *buffer = (void *)(uintptr_t)addr; + *size = buffer_size; + } + + return ret; +} + +/** * efi_load_image() - load an EFI image into memory * @boot_policy: true for request originating from the boot manager * @parent_image: the caller's image handle @@ -1883,8 +2044,8 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy, } if (!source_buffer) { - ret = efi_load_image_from_path(file_path, &dest_buffer, - &source_size); + ret = efi_load_image_from_path(boot_policy, file_path, + &dest_buffer, &source_size); if (ret != EFI_SUCCESS) goto error; } else { @@ -2404,88 +2565,6 @@ found: } /** - * efi_locate_device_path() - Get the device path and handle of an device - * implementing a protocol - * @protocol: GUID of the protocol - * @device_path: device path - * @device: handle of the device - * - * This function implements the LocateDevicePath service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * Return: status code - */ -static efi_status_t EFIAPI efi_locate_device_path( - const efi_guid_t *protocol, - struct efi_device_path **device_path, - efi_handle_t *device) -{ - struct efi_device_path *dp; - size_t i; - struct efi_handler *handler; - efi_handle_t *handles; - size_t len, len_dp; - size_t len_best = 0; - efi_uintn_t no_handles; - u8 *remainder; - efi_status_t ret; - - EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); - - if (!protocol || !device_path || !*device_path) { - ret = EFI_INVALID_PARAMETER; - goto out; - } - - /* Find end of device path */ - len = efi_dp_instance_size(*device_path); - - /* Get all handles implementing the protocol */ - ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL, - &no_handles, &handles)); - if (ret != EFI_SUCCESS) - goto out; - - for (i = 0; i < no_handles; ++i) { - /* Find the device path protocol */ - ret = efi_search_protocol(handles[i], &efi_guid_device_path, - &handler); - if (ret != EFI_SUCCESS) - continue; - dp = (struct efi_device_path *)handler->protocol_interface; - len_dp = efi_dp_instance_size(dp); - /* - * This handle can only be a better fit - * if its device path length is longer than the best fit and - * if its device path length is shorter of equal the searched - * device path. - */ - if (len_dp <= len_best || len_dp > len) - continue; - /* Check if dp is a subpath of device_path */ - if (memcmp(*device_path, dp, len_dp)) - continue; - if (!device) { - ret = EFI_INVALID_PARAMETER; - goto out; - } - *device = handles[i]; - len_best = len_dp; - } - if (len_best) { - remainder = (u8 *)*device_path + len_best; - *device_path = (struct efi_device_path *)remainder; - ret = EFI_SUCCESS; - } else { - ret = EFI_NOT_FOUND; - } -out: - return EFI_EXIT(ret); -} - -/** * efi_install_multiple_protocol_interfaces() - Install multiple protocol * interfaces * @handle: handle on which the protocol interfaces shall be installed @@ -2700,7 +2779,7 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) * * Return: status code */ -static efi_status_t efi_protocol_open( +efi_status_t efi_protocol_open( struct efi_handler *handler, void **protocol_interface, void *agent_handle, void *controller_handle, uint32_t attributes) diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 7bd1ccec450..496ef29dd84 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -376,6 +376,23 @@ static efi_status_t efi_disk_add_dev( /* Fill in object data */ if (part) { struct efi_device_path *node = efi_dp_part_node(desc, part); + struct efi_handler *handler; + void *protocol_interface; + + /* Parent must expose EFI_BLOCK_IO_PROTOCOL */ + ret = efi_search_protocol(parent, &efi_block_io_guid, &handler); + if (ret != EFI_SUCCESS) + goto error; + + /* + * Link the partition (child controller) to the block device + * (controller). + */ + ret = efi_protocol_open(handler, &protocol_interface, NULL, + &diskobj->header, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); + if (ret != EFI_SUCCESS) + goto error; diskobj->dp = efi_dp_append_node(dp_parent, node); efi_free_pool(node); @@ -453,6 +470,9 @@ static efi_status_t efi_disk_add_dev( } } return EFI_SUCCESS; +error: + efi_delete_handle(&diskobj->header); + return ret; } /** diff --git a/lib/efi_loader/efi_hii_config.c b/lib/efi_loader/efi_hii_config.c index 26ea4b9bc0a..237e8acf840 100644 --- a/lib/efi_loader/efi_hii_config.c +++ b/lib/efi_loader/efi_hii_config.c @@ -1,9 +1,13 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * EFI Human Interface Infrastructure ... Configuration + * EFI Human Interface Infrastructure ... Configuration * - * Copyright (c) 2017 Leif Lindholm - * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + * Copyright (c) 2017 Leif Lindholm + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + * + * As this is still a non-working stub and the protocol is neither required + * by the EFI shell nor by the UEFI SCT this module has been removed from + * the Makefile. */ #include <common.h> diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c index d517d686c33..4bf3b5ef684 100644 --- a/lib/efi_loader/efi_load_initrd.c +++ b/lib/efi_loader/efi_load_initrd.c @@ -12,9 +12,6 @@ #include <efi_loader.h> #include <efi_load_initrd.h> -static const efi_guid_t efi_guid_load_file2_protocol = - EFI_LOAD_FILE2_PROTOCOL_GUID; - static efi_status_t EFIAPI efi_load_file2_initrd(struct efi_load_file_protocol *this, struct efi_device_path *file_path, bool boot_policy, diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index f68b0fdc610..b17db312f78 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -77,9 +77,6 @@ efi_status_t efi_root_node_register(void) /* HII database protocol */ &efi_guid_hii_database_protocol, (void *)&efi_hii_database, - /* HII configuration routing protocol */ - &efi_guid_hii_config_routing_protocol, - (void *)&efi_hii_config_routing, #endif NULL)); efi_root->type = EFI_OBJECT_TYPE_U_BOOT_FIRMWARE; diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 0b171c1ff7b..93c9478b225 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -133,10 +133,6 @@ efi_status_t efi_init_runtime_supported(void) #ifdef CONFIG_EFI_HAVE_RUNTIME_RESET rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; #endif - if (IS_ENABLED(CONFIG_EFI_RUNTIME_UPDATE_CAPSULE)) - rt_table->runtime_services_supported |= - (EFI_RT_SUPPORTED_UPDATE_CAPSULE | - EFI_RT_SUPPORTED_QUERY_CAPSULE_CAPABILITIES); ret = efi_install_configuration_table(&efi_rt_properties_table_guid, rt_table); diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 58fb43fcdfc..426552bfa01 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -25,9 +25,12 @@ efi_selftest_crc32.o \ efi_selftest_devicepath_util.o \ efi_selftest_events.o \ efi_selftest_event_groups.o \ +efi_selftest_exception.o \ efi_selftest_exitbootservices.o \ efi_selftest_gop.o \ +efi_selftest_load_file.o \ efi_selftest_loaded_image.o \ +efi_selftest_loadimage.o \ efi_selftest_manageprotocols.o \ efi_selftest_mem.o \ efi_selftest_memory.o \ @@ -35,6 +38,8 @@ efi_selftest_open_protocol.o \ efi_selftest_register_notify.o \ efi_selftest_reset.o \ efi_selftest_set_virtual_address_map.o \ +efi_selftest_startimage_exit.o \ +efi_selftest_startimage_return.o \ efi_selftest_textinput.o \ efi_selftest_textinputex.o \ efi_selftest_textoutput.o \ @@ -65,12 +70,6 @@ ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy) obj-y += efi_selftest_block_device.o endif -obj-y += \ -efi_selftest_exception.o \ -efi_selftest_loadimage.o \ -efi_selftest_startimage_exit.o \ -efi_selftest_startimage_return.o - targets += \ efi_miniapp_file_image_exception.h \ efi_miniapp_file_image_exit.h \ @@ -94,10 +93,12 @@ $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \ $(obj)/efi_miniapp_file_image_return.h -$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h - $(obj)/efi_selftest_exception.o: $(obj)/efi_miniapp_file_image_exception.h +$(obj)/efi_selftest_load_file.o: $(obj)/efi_miniapp_file_image_exit.h + +$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h + $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h $(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h diff --git a/lib/efi_selftest/efi_selftest_load_file.c b/lib/efi_selftest/efi_selftest_load_file.c new file mode 100644 index 00000000000..4473e7c36ed --- /dev/null +++ b/lib/efi_selftest/efi_selftest_load_file.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_load_file + * + * Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This test checks the handling of the LOAD_FILE and the LOAD_FILE2 protocol + * by the LoadImage() service. + */ + +#include <efi_selftest.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_exit.h" + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +#define GUID_VENDOR \ + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \ + 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd1) + +#define GUID_VENDOR2 \ + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \ + 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd2) + +#define FILE_NAME_SIZE 16 + +static const efi_guid_t efi_st_guid_load_file_protocol = + EFI_LOAD_FILE_PROTOCOL_GUID; +static const efi_guid_t efi_st_guid_load_file2_protocol = + EFI_LOAD_FILE2_PROTOCOL_GUID; +static const efi_guid_t efi_st_guid_device_path = + EFI_DEVICE_PATH_PROTOCOL_GUID; + +static efi_handle_t image_handle; +static struct efi_boot_services *boottime; +static efi_handle_t handle_lf; +static efi_handle_t handle_lf2; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +static int load_file_call_count; +static int load_file2_call_count; + +/* Decompressed file image */ +static u8 *image; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path d; +} dp_lf_prot = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path_file_path f; + u16 file_name[FILE_NAME_SIZE]; + struct efi_device_path e; +} dp_lf_file = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR, + }, + { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16), + } + }, + L"\\lf.efi", + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +struct efi_device_path *dp_lf_file_remainder = &dp_lf_file.f.dp; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path d; +} dp_lf2_prot = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR2, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path_file_path f; + u16 file_name[FILE_NAME_SIZE]; + struct efi_device_path e; +} dp_lf2_file = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR2, + }, + { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16), + } + }, + L"\\lf2.efi", + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +struct efi_device_path *dp_lf2_file_remainder = &dp_lf2_file.f.dp; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * load_file() - LoadFile() service of a EFI_LOAD_FILE_PROTOCOL + * + * @this: instance of EFI_LOAD_FILE_PROTOCOL + * @file_path: remaining device path + * @boot_policy: true if called by boot manager + * @buffer_size: (required) buffer size + * @buffer: buffer to which the file is to be loaded + */ +efi_status_t EFIAPI load_file(struct efi_load_file_protocol *this, + struct efi_device_path *file_path, + bool boot_policy, + efi_uintn_t *buffer_size, + void *buffer) +{ + ++load_file_call_count; + if (memcmp(file_path, dp_lf_file_remainder, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16) + + sizeof(struct efi_device_path))) { + efi_st_error("Wrong remaining device path\n"); + return EFI_NOT_FOUND; + } + if (this->load_file != load_file) { + efi_st_error("wrong this\n"); + return EFI_INVALID_PARAMETER; + } + if (*buffer_size < img.length) { + *buffer_size = img.length; + return EFI_BUFFER_TOO_SMALL; + } + memcpy(buffer, image, img.length); + *buffer_size = img.length; + return EFI_SUCCESS; +} + + +/* + * load_file2() - LoadFile() service of a EFI_LOAD_FILE2_PROTOCOL + * + * @this: instance of EFI_LOAD_FILE2_PROTOCOL + * @file_path: remaining device path + * @boot_policy: true if called by boot manager + * @buffer_size: (required) buffer size + * @buffer: buffer to which the file is to be loaded + */ +efi_status_t EFIAPI load_file2(struct efi_load_file_protocol *this, + struct efi_device_path *file_path, + bool boot_policy, + efi_uintn_t *buffer_size, + void *buffer) +{ + ++load_file2_call_count; + if (memcmp(file_path, dp_lf2_file_remainder, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16) + + sizeof(struct efi_device_path))) { + efi_st_error("Wrong remaining device path\n"); + return EFI_NOT_FOUND; + } + if (this->load_file != load_file2) { + efi_st_error("wrong this\n"); + return EFI_INVALID_PARAMETER; + } + if (boot_policy) { + efi_st_error("LOAD_FILE2 called with boot_policy = true"); + return EFI_INVALID_PARAMETER; + } + if (*buffer_size < img.length) { + *buffer_size = img.length; + return EFI_BUFFER_TOO_SMALL; + } + memcpy(buffer, image, img.length); + *buffer_size = img.length; + return EFI_SUCCESS; +} + +static struct efi_load_file_protocol lf_prot = {load_file}; +static struct efi_load_file_protocol lf2_prot = {load_file2}; + +/* + * Setup unit test. + * + * Install an EFI_LOAD_FILE_PROTOCOL and an EFI_LOAD_FILE2_PROTOCOL. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + image_handle = handle; + boottime = systable->boottime; + + /* Load the application image into memory */ + decompress(&image); + + ret = boottime->install_multiple_protocol_interfaces( + &handle_lf, + &efi_st_guid_device_path, + &dp_lf_prot, + &efi_st_guid_load_file_protocol, + &lf_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_multiple_protocol_interfaces( + &handle_lf2, + &efi_st_guid_device_path, + &dp_lf2_prot, + &efi_st_guid_load_file2_protocol, + &lf2_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_teardown(void) +{ + efi_status_t ret = EFI_ST_SUCCESS; + + if (handle_lf) { + ret = boottime->uninstall_multiple_protocol_interfaces( + handle_lf, + &efi_st_guid_device_path, + &dp_lf_prot, + &efi_st_guid_load_file_protocol, + &lf_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error( + "UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + } + if (handle_lf2) { + ret = boottime->uninstall_multiple_protocol_interfaces( + handle_lf2, + &efi_st_guid_device_path, + &dp_lf2_prot, + &efi_st_guid_load_file2_protocol, + &lf2_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error( + "UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + } + + if (image) { + ret = boottime->free_pool(image); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return ret; +} + +/* + * Execute unit test. + * + * Try loading an image via the EFI_LOAD_FILE_PROTOCOL and the + * EFI_LOAD_FILE2_PROTOCOL. Finally execute the image. + * + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_execute(void) +{ + efi_status_t ret; + efi_handle_t handle; + efi_uintn_t exit_data_size = 0; + u16 *exit_data = NULL; + u16 expected_text[] = EFI_ST_SUCCESS_STR; + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(true, image_handle, &dp_lf_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (load_file2_call_count || !load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + ret = boottime->unload_image(handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unload image\n"); + return EFI_ST_FAILURE; + } + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(false, image_handle, &dp_lf_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (load_file2_call_count || !load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + ret = boottime->unload_image(handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unload image\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->load_image(true, image_handle, &dp_lf2_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_NOT_FOUND) { + efi_st_error( + "Boot manager should not use LOAD_FILE2_PROTOCOL\n"); + return EFI_ST_FAILURE; + } + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(false, image_handle, &dp_lf2_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (!load_file2_call_count || load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->start_image(handle, &exit_data_size, &exit_data); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("Wrong return value from application\n"); + return EFI_ST_FAILURE; + } + if (!exit_data || exit_data_size != sizeof(expected_text) || + memcmp(exit_data, expected_text, sizeof(expected_text))) { + efi_st_error("Incorrect exit data\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(exit_data); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free exit data\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(load_file_protocol) = { + .name = "load file protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = efi_st_load_file_setup, + .execute = efi_st_load_file_execute, + .teardown = efi_st_load_file_teardown, +}; diff --git a/lib/efi_selftest/efi_selftest_load_initrd.c b/lib/efi_selftest/efi_selftest_load_initrd.c index fe060a66440..f591dcd2115 100644 --- a/lib/efi_selftest/efi_selftest_load_initrd.c +++ b/lib/efi_selftest/efi_selftest_load_initrd.c @@ -86,7 +86,6 @@ static int setup(const efi_handle_t handle, static int execute(void) { - efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; struct efi_load_file_protocol *lf2; struct efi_device_path *dp2, *dp2_invalid; efi_status_t status; @@ -99,13 +98,15 @@ static int execute(void) memset(buffer, 0, sizeof(buffer)); dp2 = (struct efi_device_path *)&dp; - status = boottime->locate_device_path(&lf2_proto_guid, &dp2, &handle); + status = boottime->locate_device_path(&efi_guid_load_file2_protocol, + &dp2, &handle); if (status != EFI_SUCCESS) { efi_st_error("Unable to locate device path\n"); return EFI_ST_FAILURE; } - status = boottime->handle_protocol(handle, &lf2_proto_guid, + status = boottime->handle_protocol(handle, + &efi_guid_load_file2_protocol, (void **)&lf2); if (status != EFI_SUCCESS) { efi_st_error("Unable to locate protocol\n"); |