@@ -1835,6 +1835,10 @@ struct efi_signature_list {
EFI_GUID(0x86c77a67, 0x0b97, 0x4633, 0xa1, 0x87, \
0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7)
+#define EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID \
+ EFI_GUID(0xae13ff2d, 0x9ad4, 0x4e25, 0x9a, 0xc8, \
+ 0x6d, 0x80, 0xb3, 0xb2, 0x21, 0x47)
+
#define EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE 0x1
#define EFI_IMAGE_ATTRIBUTE_RESET_REQUIRED 0x2
#define EFI_IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED 0x4
@@ -86,6 +86,30 @@ config EFI_CAPSULE_FIRMWARE_MANAGEMENT
Select this option if you want to enable capsule-based
firmware update using Firmware Management Protocol.
+config EFI_CAPSULE_FIT_SIMPLE
+ bool "FMP driver for simple FIT image"
+ depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
+ depends on FIT
+ select UPDATE_TFTP
+ select DFU
+ default n
+ help
+ Select this option if you want to enable firmware management protocol
+ driver 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 (i.e. scsi, mmc and so on) 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, say 1:1, for storing FIT image
+
config EFI_DEVICE_PATH_TO_TEXT
bool "Device path to text protocol"
default y
@@ -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_HAVE_CAPSULE_SUPPORT) += 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
new file mode 100644
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EFI Firmware management protocol for FIT image
+ *
+ * Copyright (c) 2020 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <net.h>
+
+/*
+ * This FIRMWARE_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;
+}
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 <takahiro.akashi at linaro.org> --- include/efi_api.h | 4 + lib/efi_loader/Kconfig | 24 +++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_firmware.c | 191 ++++++++++++++++++++++++++++++++++ 4 files changed, 220 insertions(+) create mode 100644 lib/efi_loader/efi_firmware.c