diff mbox series

[RFC,09/14] efi_loader: add simple firmware management protocol for FIT image

Message ID 20200317021247.5849-10-takahiro.akashi@linaro.org
State New
Headers show
Series efi_loader: add capsule update support | expand

Commit Message

AKASHI Takahiro March 17, 2020, 2:12 a.m. UTC
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_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

Comments

Heinrich Schuchardt March 18, 2020, 8:04 a.m. UTC | #1
On 3/17/20 3:12 AM, AKASHI Takahiro wrote:
> 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_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

UPDATE_TFTP is a very unsecure setting. A rogue DHCP and tFTP server can
be used to compromise a device where this is enabled.

Why should we need to enable an insecure network protocol to have
capsule updates?

Best regards

Heinrich

> +	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 <common.h>
> +#include <efi_loader.h>
> +#include <net.h>
> +
> +/*
> + * 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;
> +}
>
AKASHI Takahiro March 18, 2020, 8:17 a.m. UTC | #2
On Wed, Mar 18, 2020 at 09:04:44AM +0100, Heinrich Schuchardt wrote:
> On 3/17/20 3:12 AM, AKASHI Takahiro wrote:
> > 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_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
> 
> UPDATE_TFTP is a very unsecure setting. A rogue DHCP and tFTP server can
> be used to compromise a device where this is enabled.
> 
> Why should we need to enable an insecure network protocol to have
> capsule updates?

1. This is a sample FMP driver to demonstrate a power of capsule
2. update_tftp() is called *only* against the interface and device
   that are specified by configuration. It's up to the developer.
3. Later on, capsule authentication support will be implemented.

So I believe that my approach here makes good sense.

-Takahiro Akashi

> Best regards
> 
> Heinrich
> 
> > +	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 <common.h>
> > +#include <efi_loader.h>
> > +#include <net.h>
> > +
> > +/*
> > + * 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;
> > +}
> > 
>
Heinrich Schuchardt March 18, 2020, 9:06 a.m. UTC | #3
On 3/18/20 9:17 AM, AKASHI Takahiro wrote:
> On Wed, Mar 18, 2020 at 09:04:44AM +0100, Heinrich Schuchardt wrote:
>> On 3/17/20 3:12 AM, AKASHI Takahiro wrote:
>>> 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_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
>>
>> UPDATE_TFTP is a very unsecure setting. A rogue DHCP and tFTP server can
>> be used to compromise a device where this is enabled.
>>
>> Why should we need to enable an insecure network protocol to have
>> capsule updates?
>
> 1. This is a sample FMP driver to demonstrate a power of capsule
> 2. update_tftp() is called *only* against the interface and device
>     that are specified by configuration. It's up to the developer.

I am concerned about the dhcp or tftp command becoming insecure with
CONFIG_UPDATE_TFTP=y.

I would prefer a CONFIG_UPDATE controlling if common/update.c is
compiled and a separate CONFIG_UPDATE_TFTP which enables what is tFTP
specific.

Best regards

Heinrich

> 3. Later on, capsule authentication support will be implemented.
>
> So I believe that my approach here makes good sense.
>
> -Takahiro Akashi
>
>> Best regards
>>
>> Heinrich
>>
>>> +	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 <common.h>
>>> +#include <efi_loader.h>
>>> +#include <net.h>
>>> +
>>> +/*
>>> + * 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;
>>> +}
>>>
>>
diff mbox series

Patch

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 <common.h>
+#include <efi_loader.h>
+#include <net.h>
+
+/*
+ * 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;
+}