From patchwork Tue Mar 17 02:12:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 243727 List-Id: U-Boot discussion From: takahiro.akashi at linaro.org (AKASHI Takahiro) Date: Tue, 17 Mar 2020 11:12:42 +0900 Subject: [RFC 09/14] efi_loader: add simple firmware management protocol for FIT image In-Reply-To: <20200317021247.5849-1-takahiro.akashi@linaro.org> References: <20200317021247.5849-1-takahiro.akashi@linaro.org> Message-ID: <20200317021247.5849-10-takahiro.akashi@linaro.org> In this commit, a very simple firmware management protocol driver is implemented. It will take a single FIT image firmware in a capsule and apply the data using an existing update_tftp() interface. To specify a device and location to be updated, CONFIG_EFI_CAPSULE_FIT_INTERFACE, and CONFIG_EFI_CAPSULE_FIT_DEVICE are used. Signed-off-by: AKASHI Takahiro --- include/efi_loader.h | 3 + lib/efi_loader/Kconfig | 24 ++++- lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_firmware.c | 191 ++++++++++++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_firmware.c diff --git a/include/efi_loader.h b/include/efi_loader.h index c701672e18db..79bdf9586d24 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -134,6 +134,7 @@ 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; extern const struct efi_rng_protocol efi_rng_protocol; +extern const struct efi_firmware_management_protocol efi_fmp_fit; uint16_t *efi_dp_str(struct efi_device_path *dp); @@ -180,6 +181,8 @@ extern const efi_guid_t efi_guid_hii_database_protocol; extern const efi_guid_t efi_guid_hii_string_protocol; /* GUID of capsule update result */ extern const efi_guid_t efi_guid_capsule_report; +/* GUID of firmware management protocol */ +extern const efi_guid_t efi_guid_firmware_management_protocol; /* GUID of RNG protocol */ extern const efi_guid_t efi_guid_rng_protocol; diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 43d6f75d557a..41b1e9b5543c 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -97,7 +97,6 @@ config EFI_CAPSULE_UPDATE Select this option if you want to use capsule update feature, including firmware updates and variable updates. - if EFI_CAPSULE_UPDATE config EFI_CAPSULE_UPDATE_FIRMWARE @@ -107,6 +106,29 @@ config EFI_CAPSULE_UPDATE_FIRMWARE Select this option if you want to enable capsule-based firmware update +config EFI_CAPSULE_FIT_SIMPLE + bool "Firmware management protocol for simple FIT image" + depends on EFI_CAPSULE_UPDATE_FIRMWARE + depends on FIT + select UPDATE_TFTP + select DFU + default n + help + Select this option if you want to enable firmware management protocol + for simple FIT image + +config EFI_CAPSULE_FIT_INTERFACE + string "Storage interface for storing FIT image" + depends on EFI_CAPSULE_FIT_SIMPLE + help + Define storage interface for storing FIT image + +config EFI_CAPSULE_FIT_DEVICE + string "Storage device for storing FIT image" + depends on EFI_CAPSULE_FIT_SIMPLE + help + Define storage device for storing FIT image + endif config EFI_CAPSULE_ON_DISK diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index f19096924bef..50da10e0e3d9 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_bootmgr.o obj-y += efi_boottime.o obj-$(CONFIG_EFI_CAPSULE_UPDATE) += efi_capsule.o +obj-$(CONFIG_EFI_CAPSULE_FIT_SIMPLE) += efi_firmware.o obj-y += efi_console.o obj-y += efi_device_path.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c new file mode 100644 index 000000000000..021c93196242 --- /dev/null +++ b/lib/efi_loader/efi_firmware.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI Firmware management protocol for FIT image + * + * Copyright (c) 2018 Linaro Limited + * Author: AKASHI Takahiro + */ + +#include +#include +#include + +/* + * This FIMRWARE_MANAGEMENT_PROTOCOL driver provides a simple + * firmware update method, and handles + * - a single region of firmware via DFU + * but doesn't support + * - versioning of firmware image + * - package information + */ +const efi_guid_t efi_firmware_image_type_uboot_fit = + EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; + +static +efi_status_t EFIAPI efi_fmp_fit_get_image_info( + struct efi_firmware_management_protocol *this, + efi_uintn_t *image_info_size, + struct efi_firmware_image_descriptor *image_info, + u32 *descriptor_version, + u8 *descriptor_count, + efi_uintn_t *descriptor_size, + u32 *package_version, + u16 **package_version_name) +{ + efi_status_t ret = EFI_SUCCESS; + + EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, + image_info_size, image_info, + descriptor_version, descriptor_count, descriptor_size, + package_version, package_version_name); + + if (!image_info_size) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + if (*image_info_size < sizeof(*image_info)) { + *image_info_size = sizeof(*image_info); + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + + if (!image_info) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + *image_info_size = sizeof(*image_info); + if (descriptor_version) + *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION; + if (descriptor_count) + *descriptor_count = 1; + if (descriptor_size) + *descriptor_size = sizeof(*image_info); + if (package_version) + *package_version = 0xffffffff; /* not supported */ + if (package_version_name) + *package_version_name = NULL; /* not supported */ + + image_info[0].image_index = 1; + image_info[0].image_type_id = efi_firmware_image_type_uboot_fit; + image_info[0].image_id = 0; + image_info[0].image_id_name = L"fw_simple"; + image_info[0].version = 0; /* not supported */ + image_info[0].version_name = NULL; /* not supported */ + image_info[0].size = 0; +#if defined(CONFIG_FIT) && defined(CONFIG_UPDATE_TFTP) + image_info[0].attributes_supported = + EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; + image_info[0].attributes_setting = EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; +#else + image_info[0].attributes_supported = 0; + image_info[0].attributes_setting = 0; +#endif + image_info[0].lowest_supported_image_version = 0; + image_info[0].last_attempt_version = 0; + image_info[0].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS; + image_info[0].hardware_instance = 1; + image_info[0].dependencies = NULL; + + return EFI_EXIT(ret); +} + +static +efi_status_t EFIAPI efi_fmp_fit_get_image( + struct efi_firmware_management_protocol *this, + u8 image_index, + void *image, + efi_uintn_t *image_size) +{ + EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static +efi_status_t EFIAPI efi_fmp_fit_set_image( + struct efi_firmware_management_protocol *this, + u8 image_index, + const void *image, + efi_uintn_t image_size, + const void *vendor_code, + efi_status_t (*progress)(efi_uintn_t completion), + u16 **abort_reason) +{ + EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image, + image_size, vendor_code, progress, abort_reason); + +#if defined(CONFIG_FIT) && defined(CONFIG_UPDATE_TFTP) + if (!image || image_index != 1) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + if (update_tftp((ulong)image, CONFIG_EFI_CAPSULE_FIT_INTERFACE, + CONFIG_EFI_CAPSULE_FIT_DEVICE)) + return EFI_EXIT(EFI_DEVICE_ERROR); + + return EFI_EXIT(EFI_SUCCESS); +#else + return EFI_EXIT(EFI_UNSUPPORTED); +#endif +} + +static +efi_status_t EFIAPI efi_fmp_fit_check_image( + struct efi_firmware_management_protocol *this, + u8 image_index, + const void *image, + efi_uintn_t *image_size, + u32 *image_updatable) +{ + EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size, + image_updatable); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static +efi_status_t EFIAPI efi_fmp_fit_get_package_info( + struct efi_firmware_management_protocol *this, + u32 *package_version, + u16 **package_version_name, + u32 *package_version_name_maxlen, + u64 *attributes_supported, + u64 *attributes_setting) +{ + EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version, + package_version_name, package_version_name_maxlen, + attributes_supported, attributes_setting); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +static +efi_status_t EFIAPI efi_fmp_fit_set_package_info( + struct efi_firmware_management_protocol *this, + const void *image, + efi_uintn_t *image_size, + const void *vendor_code, + u32 package_version, + const u16 *package_version_name) +{ + EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code, + package_version, package_version_name); + + return EFI_EXIT(EFI_UNSUPPORTED); +} + +const struct efi_firmware_management_protocol efi_fmp_fit_simple = { + .get_image_info = efi_fmp_fit_get_image_info, + .get_image = efi_fmp_fit_get_image, + .set_image = efi_fmp_fit_set_image, + .check_image = efi_fmp_fit_check_image, + .get_package_info = efi_fmp_fit_get_package_info, + .set_package_info = efi_fmp_fit_set_package_info, +}; + +efi_status_t arch_efi_load_capsule_drivers(void) +{ + efi_status_t ret; + + ret = EFI_CALL(efi_install_multiple_protocol_interfaces( + &efi_root, &efi_guid_firmware_management_protocol, + &efi_fmp_fit_simple, NULL)); + + return ret; +}