diff mbox series

[3/8] qemu: arm64: Add support for efi firmware management protocol routines

Message ID 20200430173630.15608-4-sughosh.ganu@linaro.org
State New
Headers show
Series qemu: arm64: Add support for uefi firmware management protocol routines | expand

Commit Message

Sughosh Ganu April 30, 2020, 5:36 p.m. UTC
Add support for the get_image_info and set_image routines, which are
part of the efi firmware management protocol.

The current implementation uses the set_image routine for updating the
u-boot binary image for the qemu arm64 platform. This is supported
using the capsule-on-disk feature of the uefi specification, wherein
the firmware image to be updated is placed on the efi system partition
as a efi capsule under EFI/UpdateCapsule/ directory. Support has been
added for updating the u-boot image on platforms booting with arm
trusted firmware(tf-a), where the u-boot image gets booted as the BL33
payload(bl33.bin).

The feature can be enabled by the following config options

CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y

Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org>
---
 board/emulation/qemu-arm/Kconfig        |  12 ++
 board/emulation/qemu-arm/Makefile       |   1 +
 board/emulation/qemu-arm/qemu_efi_fmp.c | 210 ++++++++++++++++++++++++
 3 files changed, 223 insertions(+)
 create mode 100644 board/emulation/qemu-arm/qemu_efi_fmp.c

Comments

Heinrich Schuchardt April 30, 2020, 6:39 p.m. UTC | #1
On 4/30/20 7:36 PM, Sughosh Ganu wrote:
> Add support for the get_image_info and set_image routines, which are
> part of the efi firmware management protocol.
>
> The current implementation uses the set_image routine for updating the
> u-boot binary image for the qemu arm64 platform. This is supported
> using the capsule-on-disk feature of the uefi specification, wherein
> the firmware image to be updated is placed on the efi system partition
> as a efi capsule under EFI/UpdateCapsule/ directory. Support has been
> added for updating the u-boot image on platforms booting with arm
> trusted firmware(tf-a), where the u-boot image gets booted as the BL33
> payload(bl33.bin).
>
> The feature can be enabled by the following config options
>
> CONFIG_EFI_CAPSULE_ON_DISK=y
> CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org>

U-Boot's UEFI subsystem should work in the same way for x86, ARM, and
RISC-V. Please, come up with an architecture independent solution.

Best regards

Heinrich

> ---
>  board/emulation/qemu-arm/Kconfig        |  12 ++
>  board/emulation/qemu-arm/Makefile       |   1 +
>  board/emulation/qemu-arm/qemu_efi_fmp.c | 210 ++++++++++++++++++++++++
>  3 files changed, 223 insertions(+)
>  create mode 100644 board/emulation/qemu-arm/qemu_efi_fmp.c
>
> diff --git a/board/emulation/qemu-arm/Kconfig b/board/emulation/qemu-arm/Kconfig
> index 02ae4d9884..f1b2de8e41 100644
> --- a/board/emulation/qemu-arm/Kconfig
> +++ b/board/emulation/qemu-arm/Kconfig
> @@ -11,3 +11,15 @@ config BOARD_SPECIFIC_OPTIONS # dummy
>  	imply VIRTIO_BLK
>
>  endif
> +
> +if TARGET_QEMU_ARM_64BIT && TFABOOT
> +
> +config EFI_FIRMWARE_MANAGEMENT_PROTOCOL
> +	bool "EFI Firmware Management protocol for Qemu arm64 platform"
> +	depends on EFI_CAPSULE_ON_DISK
> +	default n
> +	help
> +	  Select this option for enabling firmware management protocol
> +	  for qemu arm64 platform
> +
> +endif
> diff --git a/board/emulation/qemu-arm/Makefile b/board/emulation/qemu-arm/Makefile
> index a22d1237ff..c95ac6d233 100644
> --- a/board/emulation/qemu-arm/Makefile
> +++ b/board/emulation/qemu-arm/Makefile
> @@ -1,3 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0+
>
>  obj-y	+= qemu-arm.o
> +obj-$(CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL) += qemu_efi_fmp.o
> diff --git a/board/emulation/qemu-arm/qemu_efi_fmp.c b/board/emulation/qemu-arm/qemu_efi_fmp.c
> new file mode 100644
> index 0000000000..9baea94e6c
> --- /dev/null
> +++ b/board/emulation/qemu-arm/qemu_efi_fmp.c
> @@ -0,0 +1,210 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2020, Linaro Limited
> + */
> +
> +#include <common.h>
> +#include <charset.h>
> +#include <efi_api.h>
> +#include <efi_loader.h>
> +#include <malloc.h>
> +#include <semihosting.h>
> +
> +#define QEMU_UBOOT_IMAGE_INDEX	0x1
> +#define QEMU_UBOOT_IMAGE	0x1
> +
> +#define UBOOT_FILE		"bl33.bin"
> +
> +#define EFI_FMP_QEMU_ARM64_UBOOT_CAPSULE_ID_GUID \
> +	EFI_GUID(0xfb90808a, 0xba9a, 0x4d42, 0xb9, 0xa2, \
> +		 0xa7, 0xa9, 0x37, 0x14, 0x4a, 0xee)
> +
> +/**
> + * qemu_arm64_fmp_get_image_info() - Implement get_image_info
> + *
> + * @this:			instance of the efi_firmware_management_protocol
> + * @image_info_size:		pointer to the size of image_info buffer
> + * @image_info:			pointer to buffer which contains info on the
> + *				image
> + * @desc_version:		pointer to version number of the
> + *				efi_firmware_image_descriptor
> + * @desc_count:			pointer to the number of descriptors of the
> + *				firmware images on the device
> + * @desc_size:			pointer to the size of an individual descriptor
> + * @package_version:		version for all firmware images on the device
> + * @package_version_name:	string representing the package version name
> + *
> + * Implement the get_image_info function of the
> + * efi_firmware_management_protocol for the platform.
> + *
> + * Return: status code
> + */
> +static efi_status_t EFIAPI qemu_arm64_fmp_get_image_info(
> +	struct efi_firmware_management_protocol *this,
> +	efi_uintn_t *image_info_size,
> +	struct efi_firmware_image_descriptor *image_info,
> +	u32 *desc_version, u8 *desc_count,
> +	efi_uintn_t *desc_size, u32 *package_version,
> +	u16 **package_version_name)
> +{
> +	efi_status_t status = EFI_SUCCESS;
> +	u16 *image_id_name;
> +	const char *image_name = "Qemu Aarch64 U-Boot";
> +	const efi_guid_t image_guid = EFI_FMP_QEMU_ARM64_UBOOT_CAPSULE_ID_GUID;
> +
> +	EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size,
> +		  image_info, desc_version, desc_count, desc_size,
> +		  package_version, package_version_name);
> +
> +	/* Sanity checks */
> +	if (*image_info_size && !image_info) {
> +		status = EFI_INVALID_PARAMETER;
> +		goto back;
> +	}
> +
> +	if (*image_info_size &&
> +	    (!desc_version || !desc_count || !desc_size)) {
> +		status = EFI_INVALID_PARAMETER;
> +		goto back;
> +	}
> +
> +	if (*image_info_size < sizeof(*image_info)) {
> +		*image_info_size = sizeof(*image_info);
> +		status = EFI_BUFFER_TOO_SMALL;
> +		goto back;
> +	}
> +
> +	if (desc_version)
> +		*desc_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
> +
> +	*desc_count = 0x1;
> +	*desc_size = sizeof(*image_info);
> +
> +	if (package_version)
> +		*package_version = 0xffffffff;
> +
> +	if (package_version_name)
> +		*package_version_name = NULL;
> +
> +	image_info[0].image_type_id = image_guid;
> +	image_info[0].image_id = QEMU_UBOOT_IMAGE;
> +
> +	image_id_name = malloc(40);
> +	utf8_utf16_strcpy(&image_id_name, image_name);
> +	image_info[0].image_id_name = image_id_name;
> +
> +	/* Todo: Get a mechanism to store version information */
> +	image_info[0]. version = 0x1;
> +	image_info[0].version_name = NULL;
> +
> +	/* Todo: Need to find a mechanism to get the image size */
> +	image_info[0].size = 0;
> +
> +	image_info[0].attributes_supported =
> +		EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
> +	image_info[0].attributes_setting = EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
> +
> +	image_info[0].lowest_supported_image_version = 1;
> +	image_info[0].last_attempt_version = 0;
> +	image_info[0].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
> +	image_info[0].hardware_instance = 0;
> +
> +back:
> +	return EFI_EXIT(status);
> +}
> +
> +/**
> + * qemu_arm64_fmp_set_image() - Implement set_image
> + *
> + * @this:			instance of the efi_firmware_management_protocol
> + * @image_index:		a unique number identifying the firmware image
> + * @image:			pointer to the buffer containing the firmware
> + *				image to be updated
> + * @image_size:			pointer to size of the firmware image
> + * @vendor_code:		pointer to the vendor specific update policy
> + * @completion:			function pointer that can be invoked to report
> + *				firmware update progress
> + * @abort_reason:		string providing details if update is aborted
> + *
> + * Implement the set_image function of the efi_firmware_management_protocol
> + * for the platform. This updates the firmware image and authenticates the
> + * capsule, if authentication is enabled
> + *
> + * Return: status code
> + */
> +static efi_status_t EFIAPI qemu_arm64_fmp_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)
> +{
> +	long fd, ret;
> +	efi_status_t status = EFI_SUCCESS;
> +	char *mode = "w+b";
> +
> +	EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
> +		  image_size, vendor_code, progress, abort_reason);
> +
> +	/*
> +	 * Put a hack here to offset the size of
> +	 * the FMP_PAYLOAD_HEADER that gets added
> +	 * by the GenerateCapsule script in edk2.
> +	 */
> +	image += 0x10;
> +	image_size -= 0x10;
> +
> +	/* Do all the sanity checks first */
> +	if (!image) {
> +		status = EFI_INVALID_PARAMETER;
> +		goto back;
> +	}
> +
> +	if (image_size == 0) {
> +		status = EFI_INVALID_PARAMETER;
> +		goto back;
> +	}
> +
> +	if (image_index != QEMU_UBOOT_IMAGE_INDEX) {
> +		status = EFI_INVALID_PARAMETER;
> +		goto back;
> +	}
> +
> +	/* Do the update */
> +	fd = smh_open(UBOOT_FILE, mode);
> +	if (fd == -1) {
> +		printf("Unable to open the firmware image for writing\n");
> +		status = EFI_DEVICE_ERROR;
> +		goto back;
> +	}
> +
> +	ret = smh_write(fd, (void *)image, image_size);
> +	if (ret == -1) {
> +		printf("Error writing to the firmware image!");
> +		smh_close(fd);
> +		status = EFI_DEVICE_ERROR;
> +		goto back;
> +	}
> +
> +	printf("Capsule Update Complete\n");
> +	smh_close(fd);
> +back:
> +	return EFI_EXIT(status);
> +}
> +
> +const struct efi_firmware_management_protocol efi_qemu_arm64_fmp = {
> +	.get_image_info = qemu_arm64_fmp_get_image_info,
> +	.set_image = qemu_arm64_fmp_set_image,
> +};
> +
> +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_qemu_arm64_fmp,
> +					NULL));
> +
> +	return ret;
> +}
>
Sughosh Ganu April 30, 2020, 7:13 p.m. UTC | #2
On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:

> On 4/30/20 7:36 PM, Sughosh Ganu wrote:
> > Add support for the get_image_info and set_image routines, which are
> > part of the efi firmware management protocol.
> >
> > The current implementation uses the set_image routine for updating the
> > u-boot binary image for the qemu arm64 platform. This is supported
> > using the capsule-on-disk feature of the uefi specification, wherein
> > the firmware image to be updated is placed on the efi system partition
> > as a efi capsule under EFI/UpdateCapsule/ directory. Support has been
> > added for updating the u-boot image on platforms booting with arm
> > trusted firmware(tf-a), where the u-boot image gets booted as the BL33
> > payload(bl33.bin).
> >
> > The feature can be enabled by the following config options
> >
> > CONFIG_EFI_CAPSULE_ON_DISK=y
> > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org>
>
> U-Boot's UEFI subsystem should work in the same way for x86, ARM, and
> RISC-V. Please, come up with an architecture independent solution.
>

Please check the explanation that I gave in the other mail. If you check
the patch series, the actual capsule authentication logic has been kept
architecture agnostic, in efi_capsule.c. The fmp protocol is very much
intended for allowing platforms to define their firmware update routines.
Edk2 also has platform specific implementation of the fmp protocol under
the edk2-platforms directory.

-sughosh


>
> Best regards
>
> Heinrich
>
> > ---
> >  board/emulation/qemu-arm/Kconfig        |  12 ++
> >  board/emulation/qemu-arm/Makefile       |   1 +
> >  board/emulation/qemu-arm/qemu_efi_fmp.c | 210 ++++++++++++++++++++++++
> >  3 files changed, 223 insertions(+)
> >  create mode 100644 board/emulation/qemu-arm/qemu_efi_fmp.c
> >
> > diff --git a/board/emulation/qemu-arm/Kconfig
> b/board/emulation/qemu-arm/Kconfig
> > index 02ae4d9884..f1b2de8e41 100644
> > --- a/board/emulation/qemu-arm/Kconfig
> > +++ b/board/emulation/qemu-arm/Kconfig
> > @@ -11,3 +11,15 @@ config BOARD_SPECIFIC_OPTIONS # dummy
> >       imply VIRTIO_BLK
> >
> >  endif
> > +
> > +if TARGET_QEMU_ARM_64BIT && TFABOOT
> > +
> > +config EFI_FIRMWARE_MANAGEMENT_PROTOCOL
> > +     bool "EFI Firmware Management protocol for Qemu arm64 platform"
> > +     depends on EFI_CAPSULE_ON_DISK
> > +     default n
> > +     help
> > +       Select this option for enabling firmware management protocol
> > +       for qemu arm64 platform
> > +
> > +endif
> > diff --git a/board/emulation/qemu-arm/Makefile
> b/board/emulation/qemu-arm/Makefile
> > index a22d1237ff..c95ac6d233 100644
> > --- a/board/emulation/qemu-arm/Makefile
> > +++ b/board/emulation/qemu-arm/Makefile
> > @@ -1,3 +1,4 @@
> >  # SPDX-License-Identifier: GPL-2.0+
> >
> >  obj-y        += qemu-arm.o
> > +obj-$(CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL) += qemu_efi_fmp.o
> > diff --git a/board/emulation/qemu-arm/qemu_efi_fmp.c
> b/board/emulation/qemu-arm/qemu_efi_fmp.c
> > new file mode 100644
> > index 0000000000..9baea94e6c
> > --- /dev/null
> > +++ b/board/emulation/qemu-arm/qemu_efi_fmp.c
> > @@ -0,0 +1,210 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (c) 2020, Linaro Limited
> > + */
> > +
> > +#include <common.h>
> > +#include <charset.h>
> > +#include <efi_api.h>
> > +#include <efi_loader.h>
> > +#include <malloc.h>
> > +#include <semihosting.h>
> > +
> > +#define QEMU_UBOOT_IMAGE_INDEX       0x1
> > +#define QEMU_UBOOT_IMAGE     0x1
> > +
> > +#define UBOOT_FILE           "bl33.bin"
> > +
> > +#define EFI_FMP_QEMU_ARM64_UBOOT_CAPSULE_ID_GUID \
> > +     EFI_GUID(0xfb90808a, 0xba9a, 0x4d42, 0xb9, 0xa2, \
> > +              0xa7, 0xa9, 0x37, 0x14, 0x4a, 0xee)
> > +
> > +/**
> > + * qemu_arm64_fmp_get_image_info() - Implement get_image_info
> > + *
> > + * @this:                    instance of the
> efi_firmware_management_protocol
> > + * @image_info_size:         pointer to the size of image_info buffer
> > + * @image_info:                      pointer to buffer which contains
> info on the
> > + *                           image
> > + * @desc_version:            pointer to version number of the
> > + *                           efi_firmware_image_descriptor
> > + * @desc_count:                      pointer to the number of
> descriptors of the
> > + *                           firmware images on the device
> > + * @desc_size:                       pointer to the size of an
> individual descriptor
> > + * @package_version:         version for all firmware images on the
> device
> > + * @package_version_name:    string representing the package version
> name
> > + *
> > + * Implement the get_image_info function of the
> > + * efi_firmware_management_protocol for the platform.
> > + *
> > + * Return: status code
> > + */
> > +static efi_status_t EFIAPI qemu_arm64_fmp_get_image_info(
> > +     struct efi_firmware_management_protocol *this,
> > +     efi_uintn_t *image_info_size,
> > +     struct efi_firmware_image_descriptor *image_info,
> > +     u32 *desc_version, u8 *desc_count,
> > +     efi_uintn_t *desc_size, u32 *package_version,
> > +     u16 **package_version_name)
> > +{
> > +     efi_status_t status = EFI_SUCCESS;
> > +     u16 *image_id_name;
> > +     const char *image_name = "Qemu Aarch64 U-Boot";
> > +     const efi_guid_t image_guid =
> EFI_FMP_QEMU_ARM64_UBOOT_CAPSULE_ID_GUID;
> > +
> > +     EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size,
> > +               image_info, desc_version, desc_count, desc_size,
> > +               package_version, package_version_name);
> > +
> > +     /* Sanity checks */
> > +     if (*image_info_size && !image_info) {
> > +             status = EFI_INVALID_PARAMETER;
> > +             goto back;
> > +     }
> > +
> > +     if (*image_info_size &&
> > +         (!desc_version || !desc_count || !desc_size)) {
> > +             status = EFI_INVALID_PARAMETER;
> > +             goto back;
> > +     }
> > +
> > +     if (*image_info_size < sizeof(*image_info)) {
> > +             *image_info_size = sizeof(*image_info);
> > +             status = EFI_BUFFER_TOO_SMALL;
> > +             goto back;
> > +     }
> > +
> > +     if (desc_version)
> > +             *desc_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
> > +
> > +     *desc_count = 0x1;
> > +     *desc_size = sizeof(*image_info);
> > +
> > +     if (package_version)
> > +             *package_version = 0xffffffff;
> > +
> > +     if (package_version_name)
> > +             *package_version_name = NULL;
> > +
> > +     image_info[0].image_type_id = image_guid;
> > +     image_info[0].image_id = QEMU_UBOOT_IMAGE;
> > +
> > +     image_id_name = malloc(40);
> > +     utf8_utf16_strcpy(&image_id_name, image_name);
> > +     image_info[0].image_id_name = image_id_name;
> > +
> > +     /* Todo: Get a mechanism to store version information */
> > +     image_info[0]. version = 0x1;
> > +     image_info[0].version_name = NULL;
> > +
> > +     /* Todo: Need to find a mechanism to get the image size */
> > +     image_info[0].size = 0;
> > +
> > +     image_info[0].attributes_supported =
> > +             EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
> > +     image_info[0].attributes_setting =
> EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
> > +
> > +     image_info[0].lowest_supported_image_version = 1;
> > +     image_info[0].last_attempt_version = 0;
> > +     image_info[0].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
> > +     image_info[0].hardware_instance = 0;
> > +
> > +back:
> > +     return EFI_EXIT(status);
> > +}
> > +
> > +/**
> > + * qemu_arm64_fmp_set_image() - Implement set_image
> > + *
> > + * @this:                    instance of the
> efi_firmware_management_protocol
> > + * @image_index:             a unique number identifying the firmware
> image
> > + * @image:                   pointer to the buffer containing the
> firmware
> > + *                           image to be updated
> > + * @image_size:                      pointer to size of the firmware
> image
> > + * @vendor_code:             pointer to the vendor specific update
> policy
> > + * @completion:                      function pointer that can be
> invoked to report
> > + *                           firmware update progress
> > + * @abort_reason:            string providing details if update is
> aborted
> > + *
> > + * Implement the set_image function of the
> efi_firmware_management_protocol
> > + * for the platform. This updates the firmware image and authenticates
> the
> > + * capsule, if authentication is enabled
> > + *
> > + * Return: status code
> > + */
> > +static efi_status_t EFIAPI qemu_arm64_fmp_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)
> > +{
> > +     long fd, ret;
> > +     efi_status_t status = EFI_SUCCESS;
> > +     char *mode = "w+b";
> > +
> > +     EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
> > +               image_size, vendor_code, progress, abort_reason);
> > +
> > +     /*
> > +      * Put a hack here to offset the size of
> > +      * the FMP_PAYLOAD_HEADER that gets added
> > +      * by the GenerateCapsule script in edk2.
> > +      */
> > +     image += 0x10;
> > +     image_size -= 0x10;
> > +
> > +     /* Do all the sanity checks first */
> > +     if (!image) {
> > +             status = EFI_INVALID_PARAMETER;
> > +             goto back;
> > +     }
> > +
> > +     if (image_size == 0) {
> > +             status = EFI_INVALID_PARAMETER;
> > +             goto back;
> > +     }
> > +
> > +     if (image_index != QEMU_UBOOT_IMAGE_INDEX) {
> > +             status = EFI_INVALID_PARAMETER;
> > +             goto back;
> > +     }
> > +
> > +     /* Do the update */
> > +     fd = smh_open(UBOOT_FILE, mode);
> > +     if (fd == -1) {
> > +             printf("Unable to open the firmware image for writing\n");
> > +             status = EFI_DEVICE_ERROR;
> > +             goto back;
> > +     }
> > +
> > +     ret = smh_write(fd, (void *)image, image_size);
> > +     if (ret == -1) {
> > +             printf("Error writing to the firmware image!");
> > +             smh_close(fd);
> > +             status = EFI_DEVICE_ERROR;
> > +             goto back;
> > +     }
> > +
> > +     printf("Capsule Update Complete\n");
> > +     smh_close(fd);
> > +back:
> > +     return EFI_EXIT(status);
> > +}
> > +
> > +const struct efi_firmware_management_protocol efi_qemu_arm64_fmp = {
> > +     .get_image_info = qemu_arm64_fmp_get_image_info,
> > +     .set_image = qemu_arm64_fmp_set_image,
> > +};
> > +
> > +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_qemu_arm64_fmp,
> > +                                     NULL));
> > +
> > +     return ret;
> > +}
> >
>
>
Heinrich Schuchardt May 1, 2020, 9:33 a.m. UTC | #3
On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>
> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
> <mailto:xypron.glpk at gmx.de>> wrote:
>
>     On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>     > Add support for the get_image_info and set_image routines, which are
>     > part of the efi firmware management protocol.
>     >
>     > The current implementation uses the set_image routine for updating the
>     > u-boot binary image for the qemu arm64 platform. This is supported
>     > using the capsule-on-disk feature of the uefi specification, wherein
>     > the firmware image to be updated is placed on the efi system partition
>     > as a efi capsule under EFI/UpdateCapsule/ directory. Support has been
>     > added for updating the u-boot image on platforms booting with arm
>     > trusted firmware(tf-a), where the u-boot image gets booted as the BL33
>     > payload(bl33.bin).
>     >
>     > The feature can be enabled by the following config options
>     >
>     > CONFIG_EFI_CAPSULE_ON_DISK=y
>     > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>     >
>     > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>     <mailto:sughosh.ganu at linaro.org>>
>
>     U-Boot's UEFI subsystem should work in the same way for x86, ARM, and
>     RISC-V. Please, come up with an architecture independent solution.
>
>
> Please check the explanation that I gave in the other mail. If you check
> the patch series, the actual capsule authentication logic has been kept
> architecture agnostic, in efi_capsule.c. The fmp protocol is very much
> intended for allowing platforms to define their firmware update
> routines. Edk2 also has platform specific implementation of the fmp
> protocol under the edk2-platforms directory.
>
> -sughosh
> ?
>

My idea is that for most platforms it will be enough to have a common
FMP implementation that consumes a capsule

* with one or more binaries
* a media device path, a start address, and a truncation flag
  for each of the binaries

The protocol implementation then will write the binaries to the device
paths:

* to an SD-Card or eMMC exposing the Block IO protocol
  for most devices
* to a file in case of the Raspberry Pi or the Sandbox or QEMU
  (and truncate it if the truncation flag is set)

If for some devices like a SPI flash we do not have a media device path
yet, then the only platform specific bit would be the block device
driver exposing the media device path.

Same with a semi-hosted file: just add a driver exposing it as a media
path with an EFI_BLOCK_IO_PROTOCOL.

For security reasons it may be advisable to make the device read-only
when reaching ExitBootServices() or even better before the first
execution of StartImage(). For this purpose we could use the Reset()
service of the EFI_BLOCK_IO_PROTOCOL or provide a U-Boot specific
service in the EFI_BLOCK_IO_PROTOCOL.

Best regards

Heinrich
Grant Likely May 5, 2020, 11:15 a.m. UTC | #4
On 01/05/2020 10:33, Heinrich Schuchardt wrote:
> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>>
>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
>> <mailto:xypron.glpk at gmx.de>> wrote:
>>
>>      On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>>      > Add support for the get_image_info and set_image routines, which are
>>      > part of the efi firmware management protocol.
>>      >
>>      > The current implementation uses the set_image routine for updating the
>>      > u-boot binary image for the qemu arm64 platform. This is supported
>>      > using the capsule-on-disk feature of the uefi specification, wherein
>>      > the firmware image to be updated is placed on the efi system partition
>>      > as a efi capsule under EFI/UpdateCapsule/ directory. Support has been
>>      > added for updating the u-boot image on platforms booting with arm
>>      > trusted firmware(tf-a), where the u-boot image gets booted as the BL33
>>      > payload(bl33.bin).
>>      >
>>      > The feature can be enabled by the following config options
>>      >
>>      > CONFIG_EFI_CAPSULE_ON_DISK=y
>>      > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>>      >
>>      > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>>      <mailto:sughosh.ganu at linaro.org>>
>>
>>      U-Boot's UEFI subsystem should work in the same way for x86, ARM, and
>>      RISC-V. Please, come up with an architecture independent solution.
>>
>>
>> Please check the explanation that I gave in the other mail. If you check
>> the patch series, the actual capsule authentication logic has been kept
>> architecture agnostic, in efi_capsule.c. The fmp protocol is very much
>> intended for allowing platforms to define their firmware update
>> routines. Edk2 also has platform specific implementation of the fmp
>> protocol under the edk2-platforms directory.
>>
>> -sughosh
>>
>>
>
> My idea is that for most platforms it will be enough to have a common
> FMP implementation that consumes a capsule
>
> * with one or more binaries
> * a media device path, a start address, and a truncation flag
>    for each of the binaries
>
> The protocol implementation then will write the binaries to the device
> paths:
>
> * to an SD-Card or eMMC exposing the Block IO protocol
>    for most devices
> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>    (and truncate it if the truncation flag is set)

Does U-Boot have a common device path protocol that can be backed by
either a block device or a file on a filesystem? I didn't think it did.

In the mean time, there are at least three backends that the FMP is
going to have to deal with; the two you list above (block device & file)
and SMC backed when updating firmware is managed by the secure world.
This first implementation only handles the file-backed use case. Can we
start with that limitation and refactor when the block-device and SMC
use cases are added in? I would hate to see this functionality held up
on having to refactor other functionality in U-Boot.

> If for some devices like a SPI flash we do not have a media device path
> yet, then the only platform specific bit would be the block device
> driver exposing the media device path.
>
> Same with a semi-hosted file: just add a driver exposing it as a media
> path with an EFI_BLOCK_IO_PROTOCOL.

Sughosh and I chatted about this and took a look a the semihosting
driver. Right now it is a standalone component implementing only the
smhload command. It looks like it easily maps onto fstype_info
operations which would be a better fit than the block IO protocol. Am I
correct in assuming that would also make semihosting available to the
EFI_FILE_PROTOCOL? The FMP backend code could be common for all
filesystem targets, with the only platform specific bit being the path
to the firmware files.

How does that sound?

g.

> For security reasons it may be advisable to make the device read-only
> when reaching ExitBootServices() or even better before the first
> execution of StartImage(). For this purpose we could use the Reset()
> service of the EFI_BLOCK_IO_PROTOCOL or provide a U-Boot specific
> service in the EFI_BLOCK_IO_PROTOCOL.
>
> Best regards
>
> Heinrich
>
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
Heinrich Schuchardt May 5, 2020, 5:04 p.m. UTC | #5
On 05.05.20 13:15, Grant Likely wrote:
>
>
> On 01/05/2020 10:33, Heinrich Schuchardt wrote:
>> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>>>
>>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
>>> <mailto:xypron.glpk at gmx.de>> wrote:
>>>
>>> ???? On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>>> ???? > Add support for the get_image_info and set_image routines,
>>> which are
>>> ???? > part of the efi firmware management protocol.
>>> ???? >
>>> ???? > The current implementation uses the set_image routine for
>>> updating the
>>> ???? > u-boot binary image for the qemu arm64 platform. This is
>>> supported
>>> ???? > using the capsule-on-disk feature of the uefi specification,
>>> wherein
>>> ???? > the firmware image to be updated is placed on the efi system
>>> partition
>>> ???? > as a efi capsule under EFI/UpdateCapsule/ directory. Support
>>> has been
>>> ???? > added for updating the u-boot image on platforms booting with arm
>>> ???? > trusted firmware(tf-a), where the u-boot image gets booted as
>>> the BL33
>>> ???? > payload(bl33.bin).
>>> ???? >
>>> ???? > The feature can be enabled by the following config options
>>> ???? >
>>> ???? > CONFIG_EFI_CAPSULE_ON_DISK=y
>>> ???? > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>>> ???? >
>>> ???? > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>>> ???? <mailto:sughosh.ganu at linaro.org>>
>>>
>>> ???? U-Boot's UEFI subsystem should work in the same way for x86,
>>> ARM, and
>>> ???? RISC-V. Please, come up with an architecture independent solution.
>>>
>>>
>>> Please check the explanation that I gave in the other mail. If you check
>>> the patch series, the actual capsule authentication logic has been kept
>>> architecture agnostic, in efi_capsule.c. The fmp protocol is very much
>>> intended for allowing platforms to define their firmware update
>>> routines. Edk2 also has platform specific implementation of the fmp
>>> protocol under the edk2-platforms directory.
>>>
>>> -sughosh
>>>
>>>
>>
>> My idea is that for most platforms it will be enough to have a common
>> FMP implementation that consumes a capsule
>>
>> * with one or more binaries
>> * a media device path, a start address, and a truncation flag
>> ?? for each of the binaries
>>
>> The protocol implementation then will write the binaries to the device
>> paths:
>>
>> * to an SD-Card or eMMC exposing the Block IO protocol
>> ?? for most devices
>> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>> ?? (and truncate it if the truncation flag is set)
>
> Does U-Boot have a common device path protocol that can be backed by
> either a block device or a file on a filesystem? I didn't think it did.

A block device, a partition, and a file all can be described by an UEFI
media device path.

>
> In the mean time, there are at least three backends that the FMP is
> going to have to deal with; the two you list above (block device & file)
> and SMC backed when updating firmware is managed by the secure world.
> This first implementation only handles the file-backed use case. Can we
> start with that limitation and refactor when the block-device and SMC
> use cases are added in? I would hate to see this functionality held up
> on having to refactor other functionality in U-Boot.

I would prefer one single FMP driver for all SMC use cases. Everything
device specific should be handled in the secure world.

Is there already a protocol defined for the communication of capsule
updates between the firmware and the secure monitor, e.g. in EDK2?

Would we simply use the UpdateCapsule() call parameters and pass them
via an SMC call?

>
>> If for some devices like a SPI flash we do not have a media device path
>> yet, then the only platform specific bit would be the block device
>> driver exposing the media device path.
>>
>> Same with a semi-hosted file: just add a driver exposing it as a media
>> path with an EFI_BLOCK_IO_PROTOCOL.
>
> Sughosh and I chatted about this and took a look a the semihosting
> driver. Right now it is a standalone component implementing only the
> smhload command. It looks like it easily maps onto fstype_info
> operations which would be a better fit than the block IO protocol. Am I
> correct in assuming that would also make semihosting available to the
> EFI_FILE_PROTOCOL? The FMP backend code could be common for all
> filesystem targets, with the only platform specific bit being the path
> to the firmware files.

According to my call with Sughosh the whole semihosting thing is about
providing a testing possibility not about any real use case.

On QEMU you can easily mount an image as block device using parameters
of the qemu-system-* command. On the mounted image/block-device you can
test both file and block device based firmware updates. On the sandbox
you could use the 'host bind' command for mounting an image.

For creating a Python unit test using the sandbox is the best fit.
Takahiro already did this for his secure boot patches.

Best regards

Heinrich

>
> How does that sound?
>
> g.
>
>> For security reasons it may be advisable to make the device read-only
>> when reaching ExitBootServices() or even better before the first
>> execution of StartImage(). For this purpose we could use the Reset()
>> service of the EFI_BLOCK_IO_PROTOCOL or provide a U-Boot specific
>> service in the EFI_BLOCK_IO_PROTOCOL.
>>
>> Best regards
>>
>> Heinrich
>>
> IMPORTANT NOTICE: The contents of this email and any attachments are
> confidential and may also be privileged. If you are not the intended
> recipient, please notify the sender immediately and do not disclose the
> contents to any other person, use it for any purpose, or store or copy
> the information in any medium. Thank you.
Grant Likely May 5, 2020, 5:23 p.m. UTC | #6
On 05/05/2020 18:04, Heinrich Schuchardt wrote:
> On 05.05.20 13:15, Grant Likely wrote:
>>
>>
>> On 01/05/2020 10:33, Heinrich Schuchardt wrote:
>>> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>>>>
>>>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
>>>> <mailto:xypron.glpk at gmx.de>> wrote:
>>>>
>>>>       On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>>>>       > Add support for the get_image_info and set_image routines,
>>>> which are
>>>>       > part of the efi firmware management protocol.
>>>>       >
>>>>       > The current implementation uses the set_image routine for
>>>> updating the
>>>>       > u-boot binary image for the qemu arm64 platform. This is
>>>> supported
>>>>       > using the capsule-on-disk feature of the uefi specification,
>>>> wherein
>>>>       > the firmware image to be updated is placed on the efi system
>>>> partition
>>>>       > as a efi capsule under EFI/UpdateCapsule/ directory. Support
>>>> has been
>>>>       > added for updating the u-boot image on platforms booting with arm
>>>>       > trusted firmware(tf-a), where the u-boot image gets booted as
>>>> the BL33
>>>>       > payload(bl33.bin).
>>>>       >
>>>>       > The feature can be enabled by the following config options
>>>>       >
>>>>       > CONFIG_EFI_CAPSULE_ON_DISK=y
>>>>       > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>>>>       >
>>>>       > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>>>>       <mailto:sughosh.ganu at linaro.org>>
>>>>
>>>>       U-Boot's UEFI subsystem should work in the same way for x86,
>>>> ARM, and
>>>>       RISC-V. Please, come up with an architecture independent solution.
>>>>
>>>>
>>>> Please check the explanation that I gave in the other mail. If you check
>>>> the patch series, the actual capsule authentication logic has been kept
>>>> architecture agnostic, in efi_capsule.c. The fmp protocol is very much
>>>> intended for allowing platforms to define their firmware update
>>>> routines. Edk2 also has platform specific implementation of the fmp
>>>> protocol under the edk2-platforms directory.
>>>>
>>>> -sughosh
>>>>
>>>>
>>>
>>> My idea is that for most platforms it will be enough to have a common
>>> FMP implementation that consumes a capsule
>>>
>>> * with one or more binaries
>>> * a media device path, a start address, and a truncation flag
>>>     for each of the binaries
>>>
>>> The protocol implementation then will write the binaries to the device
>>> paths:
>>>
>>> * to an SD-Card or eMMC exposing the Block IO protocol
>>>     for most devices
>>> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>>>     (and truncate it if the truncation flag is set)
>>
>> Does U-Boot have a common device path protocol that can be backed by
>> either a block device or a file on a filesystem? I didn't think it did.
>
> A block device, a partition, and a file all can be described by an UEFI
> media device path.

Sure, from a UEFI media path, but does the underlying U-Boot
implementation have that abstraction?

>> In the mean time, there are at least three backends that the FMP is
>> going to have to deal with; the two you list above (block device & file)
>> and SMC backed when updating firmware is managed by the secure world.
>> This first implementation only handles the file-backed use case. Can we
>> start with that limitation and refactor when the block-device and SMC
>> use cases are added in? I would hate to see this functionality held up
>> on having to refactor other functionality in U-Boot.
>
> I would prefer one single FMP driver for all SMC use cases. Everything
> device specific should be handled in the secure world.

Not all platforms will be able to put firmware update into the secure
world. For instance, Not many Arm v7 platforms have trustzone accessible
to open source developers. On non-secure platforms (e.g., anything that
loads firmware from a regular filesystem on SD or eMMC) it doesn't make
much sense to loop out to secure firmware when U-Boot owns the
filesystem and the secure world would then need to coordinate with
U-Boot to commit the writes.

All of the code can certainly be in the same location, but I do think
there are three distinct generic backends for firmware updates:
- normal-world file-backed (using filesystem)
- normal-world block-backed (offsets from start of device)
- secure device backed (needs to go into secure world for unpacking and
processing regardless)

There doesn't need to be platform-specific code in any of those back
ends, but they do have different behaviour.

>
> Is there already a protocol defined for the communication of capsule
> updates between the firmware and the secure monitor, e.g. in EDK2?

Nothing defined yet (see below)

> Would we simply use the UpdateCapsule() call parameters and pass them
> via an SMC call?

If secure world is handling the update? Yes, I think a thin
UpdateCapsule() SMC makes sense, with the bonus that UpdateCapsule() at
runtime becomes feasible on U-Boot. There are a couple of people inside
Arm looking at possible interfaces. In this situation there is very
little done in normal-world at all.

[...]

>
> According to my call with Sughosh the whole semihosting thing is about
> providing a testing possibility not about any real use case.

Yes, it's for testing, but it is particularly valuable testing because
it allows the host filesystem to be exposed into QEMU. Exposing
semihosting as a generic fstype_info in U-Boot is generically useful
apart from this entire discussion!  :-)

If we rework the semihosting code to be just another FS driver, then I
think it is just an implementation detail on the file-backed firmware
update path.

> On QEMU you can easily mount an image as block device using parameters
> of the qemu-system-* command. On the mounted image/block-device you can
> test both file and block device based firmware updates. On the sandbox
> you could use the 'host bind' command for mounting an image.

Similar to the above, this would be an implementation detail on the
block-device backed firmware update path. We need both.

g.
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
Heinrich Schuchardt May 5, 2020, 5:57 p.m. UTC | #7
On 05.05.20 19:23, Grant Likely wrote:
>
>
> On 05/05/2020 18:04, Heinrich Schuchardt wrote:
>> On 05.05.20 13:15, Grant Likely wrote:
>>>
>>>
>>> On 01/05/2020 10:33, Heinrich Schuchardt wrote:
>>>> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>>>>>
>>>>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
>>>>> <mailto:xypron.glpk at gmx.de>> wrote:
>>>>>
>>>>> ????? On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>>>>> ????? > Add support for the get_image_info and set_image routines,
>>>>> which are
>>>>> ????? > part of the efi firmware management protocol.
>>>>> ????? >
>>>>> ????? > The current implementation uses the set_image routine for
>>>>> updating the
>>>>> ????? > u-boot binary image for the qemu arm64 platform. This is
>>>>> supported
>>>>> ????? > using the capsule-on-disk feature of the uefi specification,
>>>>> wherein
>>>>> ????? > the firmware image to be updated is placed on the efi system
>>>>> partition
>>>>> ????? > as a efi capsule under EFI/UpdateCapsule/ directory. Support
>>>>> has been
>>>>> ????? > added for updating the u-boot image on platforms booting
>>>>> with arm
>>>>> ????? > trusted firmware(tf-a), where the u-boot image gets booted as
>>>>> the BL33
>>>>> ????? > payload(bl33.bin).
>>>>> ????? >
>>>>> ????? > The feature can be enabled by the following config options
>>>>> ????? >
>>>>> ????? > CONFIG_EFI_CAPSULE_ON_DISK=y
>>>>> ????? > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>>>>> ????? >
>>>>> ????? > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>>>>> ????? <mailto:sughosh.ganu at linaro.org>>
>>>>>
>>>>> ????? U-Boot's UEFI subsystem should work in the same way for x86,
>>>>> ARM, and
>>>>> ????? RISC-V. Please, come up with an architecture independent
>>>>> solution.
>>>>>
>>>>>
>>>>> Please check the explanation that I gave in the other mail. If you
>>>>> check
>>>>> the patch series, the actual capsule authentication logic has been
>>>>> kept
>>>>> architecture agnostic, in efi_capsule.c. The fmp protocol is very much
>>>>> intended for allowing platforms to define their firmware update
>>>>> routines. Edk2 also has platform specific implementation of the fmp
>>>>> protocol under the edk2-platforms directory.
>>>>>
>>>>> -sughosh
>>>>>
>>>>>
>>>>
>>>> My idea is that for most platforms it will be enough to have a common
>>>> FMP implementation that consumes a capsule
>>>>
>>>> * with one or more binaries
>>>> * a media device path, a start address, and a truncation flag
>>>> ??? for each of the binaries
>>>>
>>>> The protocol implementation then will write the binaries to the device
>>>> paths:
>>>>
>>>> * to an SD-Card or eMMC exposing the Block IO protocol
>>>> ??? for most devices
>>>> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>>>> ??? (and truncate it if the truncation flag is set)
>>>
>>> Does U-Boot have a common device path protocol that can be backed by
>>> either a block device or a file on a filesystem? I didn't think it did.
>>
>> A block device, a partition, and a file all can be described by an UEFI
>> media device path.
>
> Sure, from a UEFI media path, but does the underlying U-Boot
> implementation have that abstraction?


With a file media path we can find the partition device path on which
the Simple file protocol is already installed by U-Boot.

>
>>> In the mean time, there are at least three backends that the FMP is
>>> going to have to deal with; the two you list above (block device & file)
>>> and SMC backed when updating firmware is managed by the secure world.
>>> This first implementation only handles the file-backed use case. Can we
>>> start with that limitation and refactor when the block-device and SMC
>>> use cases are added in? I would hate to see this functionality held up
>>> on having to refactor other functionality in U-Boot.
>>
>> I would prefer one single FMP driver for all SMC use cases. Everything
>> device specific should be handled in the secure world.
>
> Not all platforms will be able to put firmware update into the secure
> world. For instance, Not many Arm v7 platforms have trustzone accessible
> to open source developers. On non-secure platforms (e.g., anything that
> loads firmware from a regular filesystem on SD or eMMC) it doesn't make
> much sense to loop out to secure firmware when U-Boot owns the
> filesystem and the secure world would then need to coordinate with
> U-Boot to commit the writes.
>
> All of the code can certainly be in the same location, but I do think
> there are three distinct generic backends for firmware updates:
> - normal-world file-backed (using filesystem)
> - normal-world block-backed (offsets from start of device)

These two could be in one instance of the FMP protocol.

> - secure device backed (needs to go into secure world for unpacking and
> processing regardless)
>
> There doesn't need to be platform-specific code in any of those back
> ends, but they do have different behaviour.
>
>>
>> Is there already a protocol defined for the communication of capsule
>> updates between the firmware and the secure monitor, e.g. in EDK2?
>
> Nothing defined yet (see below)
>
>> Would we simply use the UpdateCapsule() call parameters and pass them
>> via an SMC call?
>
> If secure world is handling the update? Yes, I think a thin
> UpdateCapsule() SMC makes sense, with the bonus that UpdateCapsule() at
> runtime becomes feasible on U-Boot. There are a couple of people inside
> Arm looking at possible interfaces. In this situation there is very
> little done in normal-world at all.
>
> [...]
>
>>
>> According to my call with Sughosh the whole semihosting thing is about
>> providing a testing possibility not about any real use case.
>
> Yes, it's for testing, but it is particularly valuable testing because
> it allows the host filesystem to be exposed into QEMU. Exposing
> semihosting as a generic fstype_info in U-Boot is generically useful
> apart from this entire discussion!? :-)
>
> If we rework the semihosting code to be just another FS driver, then I
> think it is just an implementation detail on the file-backed firmware
> update path.

In this case it could be completely separate from this patch series.

Where do you see the benefit of semi-hosting compared to mounting an image?

Best regards

Heinrich

>
>> On QEMU you can easily mount an image as block device using parameters
>> of the qemu-system-* command. On the mounted image/block-device you can
>> test both file and block device based firmware updates. On the sandbox
>> you could use the 'host bind' command for mounting an image.
>
> Similar to the above, this would be an implementation detail on the
> block-device backed firmware update path. We need both.
>
> g.
> IMPORTANT NOTICE: The contents of this email and any attachments are
> confidential and may also be privileged. If you are not the intended
> recipient, please notify the sender immediately and do not disclose the
> contents to any other person, use it for any purpose, or store or copy
> the information in any medium. Thank you.
Grant Likely May 6, 2020, 3:04 p.m. UTC | #8
On 05/05/2020 18:57, Heinrich Schuchardt wrote:
> On 05.05.20 19:23, Grant Likely wrote:
>>
>>
>> On 05/05/2020 18:04, Heinrich Schuchardt wrote:
>>> On 05.05.20 13:15, Grant Likely wrote:
>>>>
>>>>
>>>> On 01/05/2020 10:33, Heinrich Schuchardt wrote:
>>>>> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>>>>>>
>>>>>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
>>>>>> <mailto:xypron.glpk at gmx.de>> wrote:
>>>>>>
>>>>>>        On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>>>>>>        > Add support for the get_image_info and set_image routines,
>>>>>> which are
>>>>>>        > part of the efi firmware management protocol.
>>>>>>        >
>>>>>>        > The current implementation uses the set_image routine for
>>>>>> updating the
>>>>>>        > u-boot binary image for the qemu arm64 platform. This is
>>>>>> supported
>>>>>>        > using the capsule-on-disk feature of the uefi specification,
>>>>>> wherein
>>>>>>        > the firmware image to be updated is placed on the efi system
>>>>>> partition
>>>>>>        > as a efi capsule under EFI/UpdateCapsule/ directory. Support
>>>>>> has been
>>>>>>        > added for updating the u-boot image on platforms booting
>>>>>> with arm
>>>>>>        > trusted firmware(tf-a), where the u-boot image gets booted as
>>>>>> the BL33
>>>>>>        > payload(bl33.bin).
>>>>>>        >
>>>>>>        > The feature can be enabled by the following config options
>>>>>>        >
>>>>>>        > CONFIG_EFI_CAPSULE_ON_DISK=y
>>>>>>        > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>>>>>>        >
>>>>>>        > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>>>>>>        <mailto:sughosh.ganu at linaro.org>>
>>>>>>
>>>>>>        U-Boot's UEFI subsystem should work in the same way for x86,
>>>>>> ARM, and
>>>>>>        RISC-V. Please, come up with an architecture independent
>>>>>> solution.
>>>>>>
>>>>>>
>>>>>> Please check the explanation that I gave in the other mail. If you
>>>>>> check
>>>>>> the patch series, the actual capsule authentication logic has been
>>>>>> kept
>>>>>> architecture agnostic, in efi_capsule.c. The fmp protocol is very much
>>>>>> intended for allowing platforms to define their firmware update
>>>>>> routines. Edk2 also has platform specific implementation of the fmp
>>>>>> protocol under the edk2-platforms directory.
>>>>>>
>>>>>> -sughosh
>>>>>>
>>>>>>
>>>>>
>>>>> My idea is that for most platforms it will be enough to have a common
>>>>> FMP implementation that consumes a capsule
>>>>>
>>>>> * with one or more binaries
>>>>> * a media device path, a start address, and a truncation flag
>>>>>      for each of the binaries
>>>>>
>>>>> The protocol implementation then will write the binaries to the device
>>>>> paths:
>>>>>
>>>>> * to an SD-Card or eMMC exposing the Block IO protocol
>>>>>      for most devices
>>>>> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>>>>>      (and truncate it if the truncation flag is set)
>>>>
>>>> Does U-Boot have a common device path protocol that can be backed by
>>>> either a block device or a file on a filesystem? I didn't think it did.
>>>
>>> A block device, a partition, and a file all can be described by an UEFI
>>> media device path.
>>
>> Sure, from a UEFI media path, but does the underlying U-Boot
>> implementation have that abstraction?
>
>
> With a file media path we can find the partition device path on which
> the Simple file protocol is already installed by U-Boot.
>
>>
>>>> In the mean time, there are at least three backends that the FMP is
>>>> going to have to deal with; the two you list above (block device & file)
>>>> and SMC backed when updating firmware is managed by the secure world.
>>>> This first implementation only handles the file-backed use case. Can we
>>>> start with that limitation and refactor when the block-device and SMC
>>>> use cases are added in? I would hate to see this functionality held up
>>>> on having to refactor other functionality in U-Boot.
>>>
>>> I would prefer one single FMP driver for all SMC use cases. Everything
>>> device specific should be handled in the secure world.
>>
>> Not all platforms will be able to put firmware update into the secure
>> world. For instance, Not many Arm v7 platforms have trustzone accessible
>> to open source developers. On non-secure platforms (e.g., anything that
>> loads firmware from a regular filesystem on SD or eMMC) it doesn't make
>> much sense to loop out to secure firmware when U-Boot owns the
>> filesystem and the secure world would then need to coordinate with
>> U-Boot to commit the writes.
>>
>> All of the code can certainly be in the same location, but I do think
>> there are three distinct generic backends for firmware updates:
>> - normal-world file-backed (using filesystem)
>> - normal-world block-backed (offsets from start of device)
>
> These two could be in one instance of the FMP protocol.
>
>> - secure device backed (needs to go into secure world for unpacking and
>> processing regardless)
>>
>> There doesn't need to be platform-specific code in any of those back
>> ends, but they do have different behaviour.
>>
>>>
>>> Is there already a protocol defined for the communication of capsule
>>> updates between the firmware and the secure monitor, e.g. in EDK2?
>>
>> Nothing defined yet (see below)
>>
>>> Would we simply use the UpdateCapsule() call parameters and pass them
>>> via an SMC call?
>>
>> If secure world is handling the update? Yes, I think a thin
>> UpdateCapsule() SMC makes sense, with the bonus that UpdateCapsule() at
>> runtime becomes feasible on U-Boot. There are a couple of people inside
>> Arm looking at possible interfaces. In this situation there is very
>> little done in normal-world at all.
>>
>> [...]
>>
>>>
>>> According to my call with Sughosh the whole semihosting thing is about
>>> providing a testing possibility not about any real use case.
>>
>> Yes, it's for testing, but it is particularly valuable testing because
>> it allows the host filesystem to be exposed into QEMU. Exposing
>> semihosting as a generic fstype_info in U-Boot is generically useful
>> apart from this entire discussion!  :-)
>>
>> If we rework the semihosting code to be just another FS driver, then I
>> think it is just an implementation detail on the file-backed firmware
>> update path.
>
> In this case it could be completely separate from this patch series.
>
> Where do you see the benefit of semi-hosting compared to mounting an image?

Both are important. We need test benches for both file and block device
update scenarios.

g.

>
> Best regards
>
> Heinrich
>
>>
>>> On QEMU you can easily mount an image as block device using parameters
>>> of the qemu-system-* command. On the mounted image/block-device you can
>>> test both file and block device based firmware updates. On the sandbox
>>> you could use the 'host bind' command for mounting an image.
>>
>> Similar to the above, this would be an implementation detail on the
>> block-device backed firmware update path. We need both.
>>
>> g.
>> IMPORTANT NOTICE: The contents of this email and any attachments are
>> confidential and may also be privileged. If you are not the intended
>> recipient, please notify the sender immediately and do not disclose the
>> contents to any other person, use it for any purpose, or store or copy
>> the information in any medium. Thank you.
>
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
AKASHI Takahiro May 7, 2020, 2:33 a.m. UTC | #9
On Fri, May 01, 2020 at 11:33:42AM +0200, Heinrich Schuchardt wrote:
> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
> >
> > On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
> > <mailto:xypron.glpk at gmx.de>> wrote:
> >
> >     On 4/30/20 7:36 PM, Sughosh Ganu wrote:
> >     > Add support for the get_image_info and set_image routines, which are
> >     > part of the efi firmware management protocol.
> >     >
> >     > The current implementation uses the set_image routine for updating the
> >     > u-boot binary image for the qemu arm64 platform. This is supported
> >     > using the capsule-on-disk feature of the uefi specification, wherein
> >     > the firmware image to be updated is placed on the efi system partition
> >     > as a efi capsule under EFI/UpdateCapsule/ directory. Support has been
> >     > added for updating the u-boot image on platforms booting with arm
> >     > trusted firmware(tf-a), where the u-boot image gets booted as the BL33
> >     > payload(bl33.bin).
> >     >
> >     > The feature can be enabled by the following config options
> >     >
> >     > CONFIG_EFI_CAPSULE_ON_DISK=y
> >     > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
> >     >
> >     > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
> >     <mailto:sughosh.ganu at linaro.org>>
> >
> >     U-Boot's UEFI subsystem should work in the same way for x86, ARM, and
> >     RISC-V. Please, come up with an architecture independent solution.
> >
> >
> > Please check the explanation that I gave in the other mail. If you check
> > the patch series, the actual capsule authentication logic has been kept
> > architecture agnostic, in efi_capsule.c. The fmp protocol is very much
> > intended for allowing platforms to define their firmware update
> > routines. Edk2 also has platform specific implementation of the fmp
> > protocol under the edk2-platforms directory.
> >
> > -sughosh
> > ?
> >
> 
> My idea is that for most platforms it will be enough to have a common
> FMP implementation that consumes a capsule
> 
> * with one or more binaries

Does this assumption apply to most platforms?
If so ("one"),

> * a media device path, a start address, and a truncation flag
>   for each of the binaries

my FIT-based patch[1] meets this assumption and there already
are backend drivers for many media (but not for semihosting :)
as dfu.
(I see little reason to re-invent another set of backend drivers.)

[1] https://lists.denx.de/pipermail/u-boot/2020-April/408767.html


> The protocol implementation then will write the binaries to the device
> paths:
> 
> * to an SD-Card or eMMC exposing the Block IO protocol
>   for most devices
> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>   (and truncate it if the truncation flag is set)
> 
> If for some devices like a SPI flash we do not have a media device path
> yet, then the only platform specific bit would be the block device
> driver exposing the media device path.
> 
> Same with a semi-hosted file: just add a driver exposing it as a media
> path with an EFI_BLOCK_IO_PROTOCOL.
> 
> For security reasons it may be advisable to make the device read-only
> when reaching ExitBootServices() or even better before the first
> execution of StartImage(). For this purpose we could use the Reset()
> service of the EFI_BLOCK_IO_PROTOCOL or provide a U-Boot specific
> service in the EFI_BLOCK_IO_PROTOCOL.
> 
> Best regards
> 
> Heinrich
Heinrich Schuchardt May 7, 2020, 8:47 p.m. UTC | #10
On 5/7/20 4:33 AM, Akashi Takahiro wrote:
> On Fri, May 01, 2020 at 11:33:42AM +0200, Heinrich Schuchardt wrote:
>> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>>>
>>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
>>> <mailto:xypron.glpk at gmx.de>> wrote:
>>>
>>>     On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>>>     > Add support for the get_image_info and set_image routines, which are
>>>     > part of the efi firmware management protocol.
>>>     >
>>>     > The current implementation uses the set_image routine for updating the
>>>     > u-boot binary image for the qemu arm64 platform. This is supported
>>>     > using the capsule-on-disk feature of the uefi specification, wherein
>>>     > the firmware image to be updated is placed on the efi system partition
>>>     > as a efi capsule under EFI/UpdateCapsule/ directory. Support has been
>>>     > added for updating the u-boot image on platforms booting with arm
>>>     > trusted firmware(tf-a), where the u-boot image gets booted as the BL33
>>>     > payload(bl33.bin).
>>>     >
>>>     > The feature can be enabled by the following config options
>>>     >
>>>     > CONFIG_EFI_CAPSULE_ON_DISK=y
>>>     > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>>>     >
>>>     > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>>>     <mailto:sughosh.ganu at linaro.org>>
>>>
>>>     U-Boot's UEFI subsystem should work in the same way for x86, ARM, and
>>>     RISC-V. Please, come up with an architecture independent solution.
>>>
>>>
>>> Please check the explanation that I gave in the other mail. If you check
>>> the patch series, the actual capsule authentication logic has been kept
>>> architecture agnostic, in efi_capsule.c. The fmp protocol is very much
>>> intended for allowing platforms to define their firmware update
>>> routines. Edk2 also has platform specific implementation of the fmp
>>> protocol under the edk2-platforms directory.
>>>
>>> -sughosh
>>> ?
>>>
>>
>> My idea is that for most platforms it will be enough to have a common
>> FMP implementation that consumes a capsule
>>
>> * with one or more binaries
>
> Does this assumption apply to most platforms?
> If so ("one"),

Raspberry uses a file in the first partition which must be FAT to store
U-Boot. The file name of U-Boot is indicated in file config.txt to the
primary boot loader.

On all other devices I own U-Boot is installed by command 'dd' writing
to the SD-Card somewhere after the DOS partition table. (When using a
GUID partition table often you have to shorten it or relocated it to
after U-Boot.) Some of the devices could alternativley use eMMC for
U-Boot (e.g. Odroid C2).

For reference have a look at
doc/README.rockchip
https://a-delacruz.github.io/ubuntu/rpi3-setup-64bit-uboot.html

Best regards

Heinrich

>
>> * a media device path, a start address, and a truncation flag
>>   for each of the binaries
>
> my FIT-based patch[1] meets this assumption and there already
> are backend drivers for many media (but not for semihosting :)
> as dfu.
> (I see little reason to re-invent another set of backend drivers.)
>
> [1] https://lists.denx.de/pipermail/u-boot/2020-April/408767.html
>
>
>> The protocol implementation then will write the binaries to the device
>> paths:
>>
>> * to an SD-Card or eMMC exposing the Block IO protocol
>>   for most devices
>> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>>   (and truncate it if the truncation flag is set)
>>
>> If for some devices like a SPI flash we do not have a media device path
>> yet, then the only platform specific bit would be the block device
>> driver exposing the media device path.
>>
>> Same with a semi-hosted file: just add a driver exposing it as a media
>> path with an EFI_BLOCK_IO_PROTOCOL.
>>
>> For security reasons it may be advisable to make the device read-only
>> when reaching ExitBootServices() or even better before the first
>> execution of StartImage(). For this purpose we could use the Reset()
>> service of the EFI_BLOCK_IO_PROTOCOL or provide a U-Boot specific
>> service in the EFI_BLOCK_IO_PROTOCOL.
>>
>> Best regards
>>
>> Heinrich
AKASHI Takahiro May 7, 2020, 11:36 p.m. UTC | #11
On Thu, May 07, 2020 at 10:47:47PM +0200, Heinrich Schuchardt wrote:
> On 5/7/20 4:33 AM, Akashi Takahiro wrote:
> > On Fri, May 01, 2020 at 11:33:42AM +0200, Heinrich Schuchardt wrote:
> >> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
> >>>
> >>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
> >>> <mailto:xypron.glpk at gmx.de>> wrote:
> >>>
> >>>     On 4/30/20 7:36 PM, Sughosh Ganu wrote:
> >>>     > Add support for the get_image_info and set_image routines, which are
> >>>     > part of the efi firmware management protocol.
> >>>     >
> >>>     > The current implementation uses the set_image routine for updating the
> >>>     > u-boot binary image for the qemu arm64 platform. This is supported
> >>>     > using the capsule-on-disk feature of the uefi specification, wherein
> >>>     > the firmware image to be updated is placed on the efi system partition
> >>>     > as a efi capsule under EFI/UpdateCapsule/ directory. Support has been
> >>>     > added for updating the u-boot image on platforms booting with arm
> >>>     > trusted firmware(tf-a), where the u-boot image gets booted as the BL33
> >>>     > payload(bl33.bin).
> >>>     >
> >>>     > The feature can be enabled by the following config options
> >>>     >
> >>>     > CONFIG_EFI_CAPSULE_ON_DISK=y
> >>>     > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
> >>>     >
> >>>     > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
> >>>     <mailto:sughosh.ganu at linaro.org>>
> >>>
> >>>     U-Boot's UEFI subsystem should work in the same way for x86, ARM, and
> >>>     RISC-V. Please, come up with an architecture independent solution.
> >>>
> >>>
> >>> Please check the explanation that I gave in the other mail. If you check
> >>> the patch series, the actual capsule authentication logic has been kept
> >>> architecture agnostic, in efi_capsule.c. The fmp protocol is very much
> >>> intended for allowing platforms to define their firmware update
> >>> routines. Edk2 also has platform specific implementation of the fmp
> >>> protocol under the edk2-platforms directory.
> >>>
> >>> -sughosh
> >>> ?
> >>>
> >>
> >> My idea is that for most platforms it will be enough to have a common
> >> FMP implementation that consumes a capsule
> >>
> >> * with one or more binaries
> >
> > Does this assumption apply to most platforms?
> > If so ("one"),
> 
> Raspberry uses a file in the first partition which must be FAT to store
> U-Boot. The file name of U-Boot is indicated in file config.txt to the
> primary boot loader.
> 
> On all other devices I own U-Boot is installed by command 'dd' writing
> to the SD-Card somewhere after the DOS partition table. (When using a
> GUID partition table often you have to shorten it or relocated it to
> after U-Boot.) Some of the devices could alternativley use eMMC for
> U-Boot (e.g. Odroid C2).

"Firmware" doesn't always mean U-Boot binary.
What I had in my mind is that it can be
  - storage for U-Boot environment variables 
  - firmware for other peripherals, or even
  - kernel(/initfs/dtb)
(Remember that FIT format potentially allows for holding them.)
So I believe that it's totally up to systems.

-Takahiro Akashi

> For reference have a look at
> doc/README.rockchip
> https://a-delacruz.github.io/ubuntu/rpi3-setup-64bit-uboot.html
> 
> Best regards
> 
> Heinrich
> 
> >
> >> * a media device path, a start address, and a truncation flag
> >>   for each of the binaries
> >
> > my FIT-based patch[1] meets this assumption and there already
> > are backend drivers for many media (but not for semihosting :)
> > as dfu.
> > (I see little reason to re-invent another set of backend drivers.)
> >
> > [1] https://lists.denx.de/pipermail/u-boot/2020-April/408767.html
> >
> >
> >> The protocol implementation then will write the binaries to the device
> >> paths:
> >>
> >> * to an SD-Card or eMMC exposing the Block IO protocol
> >>   for most devices
> >> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
> >>   (and truncate it if the truncation flag is set)
> >>
> >> If for some devices like a SPI flash we do not have a media device path
> >> yet, then the only platform specific bit would be the block device
> >> driver exposing the media device path.
> >>
> >> Same with a semi-hosted file: just add a driver exposing it as a media
> >> path with an EFI_BLOCK_IO_PROTOCOL.
> >>
> >> For security reasons it may be advisable to make the device read-only
> >> when reaching ExitBootServices() or even better before the first
> >> execution of StartImage(). For this purpose we could use the Reset()
> >> service of the EFI_BLOCK_IO_PROTOCOL or provide a U-Boot specific
> >> service in the EFI_BLOCK_IO_PROTOCOL.
> >>
> >> Best regards
> >>
> >> Heinrich
>
Heinrich Schuchardt May 9, 2020, 10:04 a.m. UTC | #12
On 5/6/20 5:04 PM, Grant Likely wrote:
>
>
> On 05/05/2020 18:57, Heinrich Schuchardt wrote:
>> On 05.05.20 19:23, Grant Likely wrote:
>>>
>>>
>>> On 05/05/2020 18:04, Heinrich Schuchardt wrote:
>>>> On 05.05.20 13:15, Grant Likely wrote:
>>>>>
>>>>>
>>>>> On 01/05/2020 10:33, Heinrich Schuchardt wrote:
>>>>>> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>>>>>>>
>>>>>>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
>>>>>>> <mailto:xypron.glpk at gmx.de>> wrote:
>>>>>>>
>>>>>>> ?????? On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>>>>>>> ?????? > Add support for the get_image_info and set_image routines,
>>>>>>> which are
>>>>>>> ?????? > part of the efi firmware management protocol.
>>>>>>> ?????? >
>>>>>>> ?????? > The current implementation uses the set_image routine for
>>>>>>> updating the
>>>>>>> ?????? > u-boot binary image for the qemu arm64 platform. This is
>>>>>>> supported
>>>>>>> ?????? > using the capsule-on-disk feature of the uefi
>>>>>>> specification,
>>>>>>> wherein
>>>>>>> ?????? > the firmware image to be updated is placed on the efi
>>>>>>> system
>>>>>>> partition
>>>>>>> ?????? > as a efi capsule under EFI/UpdateCapsule/ directory.
>>>>>>> Support
>>>>>>> has been
>>>>>>> ?????? > added for updating the u-boot image on platforms booting
>>>>>>> with arm
>>>>>>> ?????? > trusted firmware(tf-a), where the u-boot image gets
>>>>>>> booted as
>>>>>>> the BL33
>>>>>>> ?????? > payload(bl33.bin).
>>>>>>> ?????? >
>>>>>>> ?????? > The feature can be enabled by the following config options
>>>>>>> ?????? >
>>>>>>> ?????? > CONFIG_EFI_CAPSULE_ON_DISK=y
>>>>>>> ?????? > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>>>>>>> ?????? >
>>>>>>> ?????? > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>>>>>>> ?????? <mailto:sughosh.ganu at linaro.org>>
>>>>>>>
>>>>>>> ?????? U-Boot's UEFI subsystem should work in the same way for x86,
>>>>>>> ARM, and
>>>>>>> ?????? RISC-V. Please, come up with an architecture independent
>>>>>>> solution.
>>>>>>>
>>>>>>>
>>>>>>> Please check the explanation that I gave in the other mail. If you
>>>>>>> check
>>>>>>> the patch series, the actual capsule authentication logic has been
>>>>>>> kept
>>>>>>> architecture agnostic, in efi_capsule.c. The fmp protocol is very
>>>>>>> much
>>>>>>> intended for allowing platforms to define their firmware update
>>>>>>> routines. Edk2 also has platform specific implementation of the fmp
>>>>>>> protocol under the edk2-platforms directory.
>>>>>>>
>>>>>>> -sughosh
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> My idea is that for most platforms it will be enough to have a common
>>>>>> FMP implementation that consumes a capsule
>>>>>>
>>>>>> * with one or more binaries
>>>>>> * a media device path, a start address, and a truncation flag
>>>>>> ???? for each of the binaries
>>>>>>
>>>>>> The protocol implementation then will write the binaries to the
>>>>>> device
>>>>>> paths:
>>>>>>
>>>>>> * to an SD-Card or eMMC exposing the Block IO protocol
>>>>>> ???? for most devices
>>>>>> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>>>>>> ???? (and truncate it if the truncation flag is set)
>>>>>
>>>>> Does U-Boot have a common device path protocol that can be backed by
>>>>> either a block device or a file on a filesystem? I didn't think it
>>>>> did.
>>>>
>>>> A block device, a partition, and a file all can be described by an UEFI
>>>> media device path.
>>>
>>> Sure, from a UEFI media path, but does the underlying U-Boot
>>> implementation have that abstraction?
>>
>>
>> With a file media path we can find the partition device path on which
>> the Simple file protocol is already installed by U-Boot.
>>
>>>
>>>>> In the mean time, there are at least three backends that the FMP is
>>>>> going to have to deal with; the two you list above (block device &
>>>>> file)
>>>>> and SMC backed when updating firmware is managed by the secure world.
>>>>> This first implementation only handles the file-backed use case.
>>>>> Can we
>>>>> start with that limitation and refactor when the block-device and SMC
>>>>> use cases are added in? I would hate to see this functionality held up
>>>>> on having to refactor other functionality in U-Boot.
>>>>
>>>> I would prefer one single FMP driver for all SMC use cases. Everything
>>>> device specific should be handled in the secure world.
>>>
>>> Not all platforms will be able to put firmware update into the secure
>>> world. For instance, Not many Arm v7 platforms have trustzone accessible
>>> to open source developers. On non-secure platforms (e.g., anything that
>>> loads firmware from a regular filesystem on SD or eMMC) it doesn't make
>>> much sense to loop out to secure firmware when U-Boot owns the
>>> filesystem and the secure world would then need to coordinate with
>>> U-Boot to commit the writes.
>>>
>>> All of the code can certainly be in the same location, but I do think
>>> there are three distinct generic backends for firmware updates:
>>> - normal-world file-backed (using filesystem)
>>> - normal-world block-backed (offsets from start of device)
>>
>> These two could be in one instance of the FMP protocol.
>>
>>> - secure device backed (needs to go into secure world for unpacking and
>>> processing regardless)
>>>
>>> There doesn't need to be platform-specific code in any of those back
>>> ends, but they do have different behaviour.
>>>
>>>>
>>>> Is there already a protocol defined for the communication of capsule
>>>> updates between the firmware and the secure monitor, e.g. in EDK2?
>>>
>>> Nothing defined yet (see below)
>>>
>>>> Would we simply use the UpdateCapsule() call parameters and pass them
>>>> via an SMC call?
>>>
>>> If secure world is handling the update? Yes, I think a thin
>>> UpdateCapsule() SMC makes sense, with the bonus that UpdateCapsule() at
>>> runtime becomes feasible on U-Boot. There are a couple of people inside
>>> Arm looking at possible interfaces. In this situation there is very
>>> little done in normal-world at all.
>>>
>>> [...]
>>>
>>>>
>>>> According to my call with Sughosh the whole semihosting thing is about
>>>> providing a testing possibility not about any real use case.
>>>
>>> Yes, it's for testing, but it is particularly valuable testing because
>>> it allows the host filesystem to be exposed into QEMU. Exposing
>>> semihosting as a generic fstype_info in U-Boot is generically useful
>>> apart from this entire discussion!? :-)
>>>
>>> If we rework the semihosting code to be just another FS driver, then I
>>> think it is just an implementation detail on the file-backed firmware
>>> update path.
>>
>> In this case it could be completely separate from this patch series.
>>
>> Where do you see the benefit of semi-hosting compared to mounting an
>> image?
>
> Both are important. We need test benches for both file and block device
> update scenarios.
>
> g.
>
>>
>> Best regards
>>
>> Heinrich
>>
>>>
>>>> On QEMU you can easily mount an image as block device using parameters
>>>> of the qemu-system-* command. On the mounted image/block-device you can
>>>> test both file and block device based firmware updates. On the sandbox
>>>> you could use the 'host bind' command for mounting an image.
>>>
>>> Similar to the above, this would be an implementation detail on the
>>> block-device backed firmware update path. We need both.
>>>
>>> g.
>>> IMPORTANT NOTICE: The contents of this email and any attachments are
>>> confidential and may also be privileged. If you are not the intended
>>> recipient, please notify the sender immediately and do not disclose the
>>> contents to any other person, use it for any purpose, or store or copy
>>> the information in any medium. Thank you.
>>
> IMPORTANT NOTICE: The contents of this email and any attachments are
> confidential and may also be privileged. If you are not the intended
> recipient, please notify the sender immediately and do not disclose the
> contents to any other person, use it for any purpose, or store or copy
> the information in any medium. Thank you.

[08.05  23:22] <apalos> who will provide the file path protocol and
potential offsets?
[09.05  12:02] <xypron> The media device path and the offsets have to be
provided by the one who builds the capsule and the must be integral part
of the capsule.

Best regards

Heinrich
Sughosh Ganu May 10, 2020, 11:59 a.m. UTC | #13
On Sat, 9 May 2020 at 15:34, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:

> On 5/6/20 5:04 PM, Grant Likely wrote:
> >
> >
> > On 05/05/2020 18:57, Heinrich Schuchardt wrote:
> >> On 05.05.20 19:23, Grant Likely wrote:
> >>>
> >>>
> >>> On 05/05/2020 18:04, Heinrich Schuchardt wrote:
> >>>> On 05.05.20 13:15, Grant Likely wrote:
> >>>>>
> >>>>>
> >>>>> On 01/05/2020 10:33, Heinrich Schuchardt wrote:
> >>>>>> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
> >>>>>>>
> >>>>>>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <
> xypron.glpk at gmx.de
> >>>>>>> <mailto:xypron.glpk at gmx.de>> wrote:
> >>>>>>>
> >>>>>>>        On 4/30/20 7:36 PM, Sughosh Ganu wrote:
> >>>>>>>        > Add support for the get_image_info and set_image routines,
> >>>>>>> which are
> >>>>>>>        > part of the efi firmware management protocol.
> >>>>>>>        >
> >>>>>>>        > The current implementation uses the set_image routine for
> >>>>>>> updating the
> >>>>>>>        > u-boot binary image for the qemu arm64 platform. This is
> >>>>>>> supported
> >>>>>>>        > using the capsule-on-disk feature of the uefi
> >>>>>>> specification,
> >>>>>>> wherein
> >>>>>>>        > the firmware image to be updated is placed on the efi
> >>>>>>> system
> >>>>>>> partition
> >>>>>>>        > as a efi capsule under EFI/UpdateCapsule/ directory.
> >>>>>>> Support
> >>>>>>> has been
> >>>>>>>        > added for updating the u-boot image on platforms booting
> >>>>>>> with arm
> >>>>>>>        > trusted firmware(tf-a), where the u-boot image gets
> >>>>>>> booted as
> >>>>>>> the BL33
> >>>>>>>        > payload(bl33.bin).
> >>>>>>>        >
> >>>>>>>        > The feature can be enabled by the following config options
> >>>>>>>        >
> >>>>>>>        > CONFIG_EFI_CAPSULE_ON_DISK=y
> >>>>>>>        > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
> >>>>>>>        >
> >>>>>>>        > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
> >>>>>>>        <mailto:sughosh.ganu at linaro.org>>
> >>>>>>>
> >>>>>>>        U-Boot's UEFI subsystem should work in the same way for x86,
> >>>>>>> ARM, and
> >>>>>>>        RISC-V. Please, come up with an architecture independent
> >>>>>>> solution.
> >>>>>>>
> >>>>>>>
> >>>>>>> Please check the explanation that I gave in the other mail. If you
> >>>>>>> check
> >>>>>>> the patch series, the actual capsule authentication logic has been
> >>>>>>> kept
> >>>>>>> architecture agnostic, in efi_capsule.c. The fmp protocol is very
> >>>>>>> much
> >>>>>>> intended for allowing platforms to define their firmware update
> >>>>>>> routines. Edk2 also has platform specific implementation of the fmp
> >>>>>>> protocol under the edk2-platforms directory.
> >>>>>>>
> >>>>>>> -sughosh
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>>> My idea is that for most platforms it will be enough to have a
> common
> >>>>>> FMP implementation that consumes a capsule
> >>>>>>
> >>>>>> * with one or more binaries
> >>>>>> * a media device path, a start address, and a truncation flag
> >>>>>>      for each of the binaries
> >>>>>>
> >>>>>> The protocol implementation then will write the binaries to the
> >>>>>> device
> >>>>>> paths:
> >>>>>>
> >>>>>> * to an SD-Card or eMMC exposing the Block IO protocol
> >>>>>>      for most devices
> >>>>>> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
> >>>>>>      (and truncate it if the truncation flag is set)
> >>>>>
> >>>>> Does U-Boot have a common device path protocol that can be backed by
> >>>>> either a block device or a file on a filesystem? I didn't think it
> >>>>> did.
> >>>>
> >>>> A block device, a partition, and a file all can be described by an
> UEFI
> >>>> media device path.
> >>>
> >>> Sure, from a UEFI media path, but does the underlying U-Boot
> >>> implementation have that abstraction?
> >>
> >>
> >> With a file media path we can find the partition device path on which
> >> the Simple file protocol is already installed by U-Boot.
> >>
> >>>
> >>>>> In the mean time, there are at least three backends that the FMP is
> >>>>> going to have to deal with; the two you list above (block device &
> >>>>> file)
> >>>>> and SMC backed when updating firmware is managed by the secure world.
> >>>>> This first implementation only handles the file-backed use case.
> >>>>> Can we
> >>>>> start with that limitation and refactor when the block-device and SMC
> >>>>> use cases are added in? I would hate to see this functionality held
> up
> >>>>> on having to refactor other functionality in U-Boot.
> >>>>
> >>>> I would prefer one single FMP driver for all SMC use cases. Everything
> >>>> device specific should be handled in the secure world.
> >>>
> >>> Not all platforms will be able to put firmware update into the secure
> >>> world. For instance, Not many Arm v7 platforms have trustzone
> accessible
> >>> to open source developers. On non-secure platforms (e.g., anything that
> >>> loads firmware from a regular filesystem on SD or eMMC) it doesn't make
> >>> much sense to loop out to secure firmware when U-Boot owns the
> >>> filesystem and the secure world would then need to coordinate with
> >>> U-Boot to commit the writes.
> >>>
> >>> All of the code can certainly be in the same location, but I do think
> >>> there are three distinct generic backends for firmware updates:
> >>> - normal-world file-backed (using filesystem)
> >>> - normal-world block-backed (offsets from start of device)
> >>
> >> These two could be in one instance of the FMP protocol.
> >>
> >>> - secure device backed (needs to go into secure world for unpacking and
> >>> processing regardless)
> >>>
> >>> There doesn't need to be platform-specific code in any of those back
> >>> ends, but they do have different behaviour.
> >>>
> >>>>
> >>>> Is there already a protocol defined for the communication of capsule
> >>>> updates between the firmware and the secure monitor, e.g. in EDK2?
> >>>
> >>> Nothing defined yet (see below)
> >>>
> >>>> Would we simply use the UpdateCapsule() call parameters and pass them
> >>>> via an SMC call?
> >>>
> >>> If secure world is handling the update? Yes, I think a thin
> >>> UpdateCapsule() SMC makes sense, with the bonus that UpdateCapsule() at
> >>> runtime becomes feasible on U-Boot. There are a couple of people inside
> >>> Arm looking at possible interfaces. In this situation there is very
> >>> little done in normal-world at all.
> >>>
> >>> [...]
> >>>
> >>>>
> >>>> According to my call with Sughosh the whole semihosting thing is about
> >>>> providing a testing possibility not about any real use case.
> >>>
> >>> Yes, it's for testing, but it is particularly valuable testing because
> >>> it allows the host filesystem to be exposed into QEMU. Exposing
> >>> semihosting as a generic fstype_info in U-Boot is generically useful
> >>> apart from this entire discussion!  :-)
> >>>
> >>> If we rework the semihosting code to be just another FS driver, then I
> >>> think it is just an implementation detail on the file-backed firmware
> >>> update path.
> >>
> >> In this case it could be completely separate from this patch series.
> >>
> >> Where do you see the benefit of semi-hosting compared to mounting an
> >> image?
> >
> > Both are important. We need test benches for both file and block device
> > update scenarios.
> >
> > g.
> >
> >>
> >> Best regards
> >>
> >> Heinrich
> >>
> >>>
> >>>> On QEMU you can easily mount an image as block device using parameters
> >>>> of the qemu-system-* command. On the mounted image/block-device you
> can
> >>>> test both file and block device based firmware updates. On the sandbox
> >>>> you could use the 'host bind' command for mounting an image.
> >>>
> >>> Similar to the above, this would be an implementation detail on the
> >>> block-device backed firmware update path. We need both.
> >>>
> >>> g.
> >>> IMPORTANT NOTICE: The contents of this email and any attachments are
> >>> confidential and may also be privileged. If you are not the intended
> >>> recipient, please notify the sender immediately and do not disclose the
> >>> contents to any other person, use it for any purpose, or store or copy
> >>> the information in any medium. Thank you.
> >>
> > IMPORTANT NOTICE: The contents of this email and any attachments are
> > confidential and may also be privileged. If you are not the intended
> > recipient, please notify the sender immediately and do not disclose the
> > contents to any other person, use it for any purpose, or store or copy
> > the information in any medium. Thank you.
>
> [08.05  23:22] <apalos> who will provide the file path protocol and
> potential offsets?
> [09.05  12:02] <xypron> The media device path and the offsets have to be
> provided by the one who builds the capsule and the must be integral part
> of the capsule.
>

Which part of the capsule do you propose to have this information. The
Firmware management protocol capsule structure does have vendor code,
which, as per the spec is vendor specific binary code which can be used to
"implement vendor-specific firmware image update policy". There is no
provision for passing such information as part of the capsule. Why can we
not get this information from the platform code. Is there any issue with
getting the media device path and offset information from the platform.

-sughosh
Grant Likely May 18, 2020, 5:14 p.m. UTC | #14
On 09/05/2020 11:04, Heinrich Schuchardt wrote:
> On 5/6/20 5:04 PM, Grant Likely wrote:
>>
>>
>> On 05/05/2020 18:57, Heinrich Schuchardt wrote:
>>> On 05.05.20 19:23, Grant Likely wrote:
>>>>
>>>>
>>>> On 05/05/2020 18:04, Heinrich Schuchardt wrote:
>>>>> On 05.05.20 13:15, Grant Likely wrote:
>>>>>>
>>>>>>
>>>>>> On 01/05/2020 10:33, Heinrich Schuchardt wrote:
>>>>>>> On 4/30/20 9:13 PM, Sughosh Ganu wrote:
>>>>>>>>
>>>>>>>> On Fri, 1 May 2020 at 00:09, Heinrich Schuchardt <xypron.glpk at gmx.de
>>>>>>>> <mailto:xypron.glpk at gmx.de>> wrote:
>>>>>>>>
>>>>>>>>         On 4/30/20 7:36 PM, Sughosh Ganu wrote:
>>>>>>>>         > Add support for the get_image_info and set_image routines,
>>>>>>>> which are
>>>>>>>>         > part of the efi firmware management protocol.
>>>>>>>>         >
>>>>>>>>         > The current implementation uses the set_image routine for
>>>>>>>> updating the
>>>>>>>>         > u-boot binary image for the qemu arm64 platform. This is
>>>>>>>> supported
>>>>>>>>         > using the capsule-on-disk feature of the uefi
>>>>>>>> specification,
>>>>>>>> wherein
>>>>>>>>         > the firmware image to be updated is placed on the efi
>>>>>>>> system
>>>>>>>> partition
>>>>>>>>         > as a efi capsule under EFI/UpdateCapsule/ directory.
>>>>>>>> Support
>>>>>>>> has been
>>>>>>>>         > added for updating the u-boot image on platforms booting
>>>>>>>> with arm
>>>>>>>>         > trusted firmware(tf-a), where the u-boot image gets
>>>>>>>> booted as
>>>>>>>> the BL33
>>>>>>>>         > payload(bl33.bin).
>>>>>>>>         >
>>>>>>>>         > The feature can be enabled by the following config options
>>>>>>>>         >
>>>>>>>>         > CONFIG_EFI_CAPSULE_ON_DISK=y
>>>>>>>>         > CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y
>>>>>>>>         >
>>>>>>>>         > Signed-off-by: Sughosh Ganu <sughosh.ganu at linaro.org
>>>>>>>>         <mailto:sughosh.ganu at linaro.org>>
>>>>>>>>
>>>>>>>>         U-Boot's UEFI subsystem should work in the same way for x86,
>>>>>>>> ARM, and
>>>>>>>>         RISC-V. Please, come up with an architecture independent
>>>>>>>> solution.
>>>>>>>>
>>>>>>>>
>>>>>>>> Please check the explanation that I gave in the other mail. If you
>>>>>>>> check
>>>>>>>> the patch series, the actual capsule authentication logic has been
>>>>>>>> kept
>>>>>>>> architecture agnostic, in efi_capsule.c. The fmp protocol is very
>>>>>>>> much
>>>>>>>> intended for allowing platforms to define their firmware update
>>>>>>>> routines. Edk2 also has platform specific implementation of the fmp
>>>>>>>> protocol under the edk2-platforms directory.
>>>>>>>>
>>>>>>>> -sughosh
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> My idea is that for most platforms it will be enough to have a common
>>>>>>> FMP implementation that consumes a capsule
>>>>>>>
>>>>>>> * with one or more binaries
>>>>>>> * a media device path, a start address, and a truncation flag
>>>>>>>       for each of the binaries
>>>>>>>
>>>>>>> The protocol implementation then will write the binaries to the
>>>>>>> device
>>>>>>> paths:
>>>>>>>
>>>>>>> * to an SD-Card or eMMC exposing the Block IO protocol
>>>>>>>       for most devices
>>>>>>> * to a file in case of the Raspberry Pi or the Sandbox or QEMU
>>>>>>>       (and truncate it if the truncation flag is set)
>>>>>>
>>>>>> Does U-Boot have a common device path protocol that can be backed by
>>>>>> either a block device or a file on a filesystem? I didn't think it
>>>>>> did.
>>>>>
>>>>> A block device, a partition, and a file all can be described by an UEFI
>>>>> media device path.
>>>>
>>>> Sure, from a UEFI media path, but does the underlying U-Boot
>>>> implementation have that abstraction?
>>>
>>>
>>> With a file media path we can find the partition device path on which
>>> the Simple file protocol is already installed by U-Boot.
>>>
>>>>
>>>>>> In the mean time, there are at least three backends that the FMP is
>>>>>> going to have to deal with; the two you list above (block device &
>>>>>> file)
>>>>>> and SMC backed when updating firmware is managed by the secure world.
>>>>>> This first implementation only handles the file-backed use case.
>>>>>> Can we
>>>>>> start with that limitation and refactor when the block-device and SMC
>>>>>> use cases are added in? I would hate to see this functionality held up
>>>>>> on having to refactor other functionality in U-Boot.
>>>>>
>>>>> I would prefer one single FMP driver for all SMC use cases. Everything
>>>>> device specific should be handled in the secure world.
>>>>
>>>> Not all platforms will be able to put firmware update into the secure
>>>> world. For instance, Not many Arm v7 platforms have trustzone accessible
>>>> to open source developers. On non-secure platforms (e.g., anything that
>>>> loads firmware from a regular filesystem on SD or eMMC) it doesn't make
>>>> much sense to loop out to secure firmware when U-Boot owns the
>>>> filesystem and the secure world would then need to coordinate with
>>>> U-Boot to commit the writes.
>>>>
>>>> All of the code can certainly be in the same location, but I do think
>>>> there are three distinct generic backends for firmware updates:
>>>> - normal-world file-backed (using filesystem)
>>>> - normal-world block-backed (offsets from start of device)
>>>
>>> These two could be in one instance of the FMP protocol.
>>>
>>>> - secure device backed (needs to go into secure world for unpacking and
>>>> processing regardless)
>>>>
>>>> There doesn't need to be platform-specific code in any of those back
>>>> ends, but they do have different behaviour.
>>>>
>>>>>
>>>>> Is there already a protocol defined for the communication of capsule
>>>>> updates between the firmware and the secure monitor, e.g. in EDK2?
>>>>
>>>> Nothing defined yet (see below)
>>>>
>>>>> Would we simply use the UpdateCapsule() call parameters and pass them
>>>>> via an SMC call?
>>>>
>>>> If secure world is handling the update? Yes, I think a thin
>>>> UpdateCapsule() SMC makes sense, with the bonus that UpdateCapsule() at
>>>> runtime becomes feasible on U-Boot. There are a couple of people inside
>>>> Arm looking at possible interfaces. In this situation there is very
>>>> little done in normal-world at all.
>>>>
>>>> [...]
>>>>
>>>>>
>>>>> According to my call with Sughosh the whole semihosting thing is about
>>>>> providing a testing possibility not about any real use case.
>>>>
>>>> Yes, it's for testing, but it is particularly valuable testing because
>>>> it allows the host filesystem to be exposed into QEMU. Exposing
>>>> semihosting as a generic fstype_info in U-Boot is generically useful
>>>> apart from this entire discussion!  :-)
>>>>
>>>> If we rework the semihosting code to be just another FS driver, then I
>>>> think it is just an implementation detail on the file-backed firmware
>>>> update path.
>>>
>>> In this case it could be completely separate from this patch series.
>>>
>>> Where do you see the benefit of semi-hosting compared to mounting an
>>> image?
>>
>> Both are important. We need test benches for both file and block device
>> update scenarios.
>>
>> g.
>>
>>>
>>> Best regards
>>>
>>> Heinrich
>>>
>>>>
>>>>> On QEMU you can easily mount an image as block device using parameters
>>>>> of the qemu-system-* command. On the mounted image/block-device you can
>>>>> test both file and block device based firmware updates. On the sandbox
>>>>> you could use the 'host bind' command for mounting an image.
>>>>
>>>> Similar to the above, this would be an implementation detail on the
>>>> block-device backed firmware update path. We need both.
>>>>
>>>> g.
>>>> IMPORTANT NOTICE: The contents of this email and any attachments are
>>>> confidential and may also be privileged. If you are not the intended
>>>> recipient, please notify the sender immediately and do not disclose the
>>>> contents to any other person, use it for any purpose, or store or copy
>>>> the information in any medium. Thank you.
>>>
>> IMPORTANT NOTICE: The contents of this email and any attachments are
>> confidential and may also be privileged. If you are not the intended
>> recipient, please notify the sender immediately and do not disclose the
>> contents to any other person, use it for any purpose, or store or copy
>> the information in any medium. Thank you.
>
> [08.05  23:22] <apalos> who will provide the file path protocol and
> potential offsets?
> [09.05  12:02] <xypron> The media device path and the offsets have to be
> provided by the one who builds the capsule and the must be integral part
> of the capsule.
>
> Best regards

I'm not convinced that is true. The capsule may not be able to have that
information. In the case of A/B updates, the firmware needs to track
between the active and inactive copies, and always write the firmware to
the appropriate location. I think it makes more sense for each firmware
blob to be identified for what it is, and the firmware know the location
where each image should be written (or at least have a default write
location built in; there will probably be exceptions once in a while)

g.
>
> Heinrich
>
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
diff mbox series

Patch

diff --git a/board/emulation/qemu-arm/Kconfig b/board/emulation/qemu-arm/Kconfig
index 02ae4d9884..f1b2de8e41 100644
--- a/board/emulation/qemu-arm/Kconfig
+++ b/board/emulation/qemu-arm/Kconfig
@@ -11,3 +11,15 @@  config BOARD_SPECIFIC_OPTIONS # dummy
 	imply VIRTIO_BLK
 
 endif
+
+if TARGET_QEMU_ARM_64BIT && TFABOOT
+
+config EFI_FIRMWARE_MANAGEMENT_PROTOCOL
+	bool "EFI Firmware Management protocol for Qemu arm64 platform"
+	depends on EFI_CAPSULE_ON_DISK
+	default n
+	help
+	  Select this option for enabling firmware management protocol
+	  for qemu arm64 platform
+
+endif
diff --git a/board/emulation/qemu-arm/Makefile b/board/emulation/qemu-arm/Makefile
index a22d1237ff..c95ac6d233 100644
--- a/board/emulation/qemu-arm/Makefile
+++ b/board/emulation/qemu-arm/Makefile
@@ -1,3 +1,4 @@ 
 # SPDX-License-Identifier: GPL-2.0+
 
 obj-y	+= qemu-arm.o
+obj-$(CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL) += qemu_efi_fmp.o
diff --git a/board/emulation/qemu-arm/qemu_efi_fmp.c b/board/emulation/qemu-arm/qemu_efi_fmp.c
new file mode 100644
index 0000000000..9baea94e6c
--- /dev/null
+++ b/board/emulation/qemu-arm/qemu_efi_fmp.c
@@ -0,0 +1,210 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020, Linaro Limited
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <efi_api.h>
+#include <efi_loader.h>
+#include <malloc.h>
+#include <semihosting.h>
+
+#define QEMU_UBOOT_IMAGE_INDEX	0x1
+#define QEMU_UBOOT_IMAGE	0x1
+
+#define UBOOT_FILE		"bl33.bin"
+
+#define EFI_FMP_QEMU_ARM64_UBOOT_CAPSULE_ID_GUID \
+	EFI_GUID(0xfb90808a, 0xba9a, 0x4d42, 0xb9, 0xa2, \
+		 0xa7, 0xa9, 0x37, 0x14, 0x4a, 0xee)
+
+/**
+ * qemu_arm64_fmp_get_image_info() - Implement get_image_info
+ *
+ * @this:			instance of the efi_firmware_management_protocol
+ * @image_info_size:		pointer to the size of image_info buffer
+ * @image_info:			pointer to buffer which contains info on the
+ *				image
+ * @desc_version:		pointer to version number of the
+ *				efi_firmware_image_descriptor
+ * @desc_count:			pointer to the number of descriptors of the
+ *				firmware images on the device
+ * @desc_size:			pointer to the size of an individual descriptor
+ * @package_version:		version for all firmware images on the device
+ * @package_version_name:	string representing the package version name
+ *
+ * Implement the get_image_info function of the
+ * efi_firmware_management_protocol for the platform.
+ *
+ * Return: status code
+ */
+static efi_status_t EFIAPI qemu_arm64_fmp_get_image_info(
+	struct efi_firmware_management_protocol *this,
+	efi_uintn_t *image_info_size,
+	struct efi_firmware_image_descriptor *image_info,
+	u32 *desc_version, u8 *desc_count,
+	efi_uintn_t *desc_size, u32 *package_version,
+	u16 **package_version_name)
+{
+	efi_status_t status = EFI_SUCCESS;
+	u16 *image_id_name;
+	const char *image_name = "Qemu Aarch64 U-Boot";
+	const efi_guid_t image_guid = EFI_FMP_QEMU_ARM64_UBOOT_CAPSULE_ID_GUID;
+
+	EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size,
+		  image_info, desc_version, desc_count, desc_size,
+		  package_version, package_version_name);
+
+	/* Sanity checks */
+	if (*image_info_size && !image_info) {
+		status = EFI_INVALID_PARAMETER;
+		goto back;
+	}
+
+	if (*image_info_size &&
+	    (!desc_version || !desc_count || !desc_size)) {
+		status = EFI_INVALID_PARAMETER;
+		goto back;
+	}
+
+	if (*image_info_size < sizeof(*image_info)) {
+		*image_info_size = sizeof(*image_info);
+		status = EFI_BUFFER_TOO_SMALL;
+		goto back;
+	}
+
+	if (desc_version)
+		*desc_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
+
+	*desc_count = 0x1;
+	*desc_size = sizeof(*image_info);
+
+	if (package_version)
+		*package_version = 0xffffffff;
+
+	if (package_version_name)
+		*package_version_name = NULL;
+
+	image_info[0].image_type_id = image_guid;
+	image_info[0].image_id = QEMU_UBOOT_IMAGE;
+
+	image_id_name = malloc(40);
+	utf8_utf16_strcpy(&image_id_name, image_name);
+	image_info[0].image_id_name = image_id_name;
+
+	/* Todo: Get a mechanism to store version information */
+	image_info[0]. version = 0x1;
+	image_info[0].version_name = NULL;
+
+	/* Todo: Need to find a mechanism to get the image size */
+	image_info[0].size = 0;
+
+	image_info[0].attributes_supported =
+		EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+	image_info[0].attributes_setting = EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+
+	image_info[0].lowest_supported_image_version = 1;
+	image_info[0].last_attempt_version = 0;
+	image_info[0].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
+	image_info[0].hardware_instance = 0;
+
+back:
+	return EFI_EXIT(status);
+}
+
+/**
+ * qemu_arm64_fmp_set_image() - Implement set_image
+ *
+ * @this:			instance of the efi_firmware_management_protocol
+ * @image_index:		a unique number identifying the firmware image
+ * @image:			pointer to the buffer containing the firmware
+ *				image to be updated
+ * @image_size:			pointer to size of the firmware image
+ * @vendor_code:		pointer to the vendor specific update policy
+ * @completion:			function pointer that can be invoked to report
+ *				firmware update progress
+ * @abort_reason:		string providing details if update is aborted
+ *
+ * Implement the set_image function of the efi_firmware_management_protocol
+ * for the platform. This updates the firmware image and authenticates the
+ * capsule, if authentication is enabled
+ *
+ * Return: status code
+ */
+static efi_status_t EFIAPI qemu_arm64_fmp_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)
+{
+	long fd, ret;
+	efi_status_t status = EFI_SUCCESS;
+	char *mode = "w+b";
+
+	EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
+		  image_size, vendor_code, progress, abort_reason);
+
+	/*
+	 * Put a hack here to offset the size of
+	 * the FMP_PAYLOAD_HEADER that gets added
+	 * by the GenerateCapsule script in edk2.
+	 */
+	image += 0x10;
+	image_size -= 0x10;
+
+	/* Do all the sanity checks first */
+	if (!image) {
+		status = EFI_INVALID_PARAMETER;
+		goto back;
+	}
+
+	if (image_size == 0) {
+		status = EFI_INVALID_PARAMETER;
+		goto back;
+	}
+
+	if (image_index != QEMU_UBOOT_IMAGE_INDEX) {
+		status = EFI_INVALID_PARAMETER;
+		goto back;
+	}
+
+	/* Do the update */
+	fd = smh_open(UBOOT_FILE, mode);
+	if (fd == -1) {
+		printf("Unable to open the firmware image for writing\n");
+		status = EFI_DEVICE_ERROR;
+		goto back;
+	}
+
+	ret = smh_write(fd, (void *)image, image_size);
+	if (ret == -1) {
+		printf("Error writing to the firmware image!");
+		smh_close(fd);
+		status = EFI_DEVICE_ERROR;
+		goto back;
+	}
+
+	printf("Capsule Update Complete\n");
+	smh_close(fd);
+back:
+	return EFI_EXIT(status);
+}
+
+const struct efi_firmware_management_protocol efi_qemu_arm64_fmp = {
+	.get_image_info = qemu_arm64_fmp_get_image_info,
+	.set_image = qemu_arm64_fmp_set_image,
+};
+
+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_qemu_arm64_fmp,
+					NULL));
+
+	return ret;
+}