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.g...@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;
> +}
>

Reply via email to