[PATCH 3/8] qemu: arm64: Add support for efi firmware management protocol routines
Sughosh Ganu
sughosh.ganu at linaro.org
Thu Apr 30 21:13:38 CEST 2020
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;
> > +}
> >
>
>
More information about the U-Boot
mailing list