Message ID | 20200323071201.5992-5-sughosh.ganu@linaro.org |
---|---|
State | New |
Headers | show |
Series | qemu: arm64: Add support for uefi firmware management protocol routines | expand |
Sughosh, On Mon, Mar 23, 2020 at 12:42:01PM +0530, 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. > > 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 | 173 ++++++++++++++++++++++++ > 3 files changed, 186 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..1ef2a27539 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 > + > +config EFI_FIRMWARE_MANAGEMENT_PROTOCOL I think that we should give it a qemu-specific configuration name as there can co-exist multiple drivers of FMP at the same time. > + bool "EFI Firmware Management protocol for Qemu arm64 platform" > + depends on EFI_CAPSULE_UPDATE && EFI_CAPSULE_UPDATE_FIRMWARE Please add a dependency on SEMIHOSTING with some description. > + 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..17caa59786 > --- /dev/null > +++ b/board/emulation/qemu-arm/qemu_efi_fmp.c > @@ -0,0 +1,173 @@ > +// 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" It would be better to parameterize this file name as a configuration option so as to make this solution more generic for TFA-based and non-TFA-based system. -Takahiro Akashi > +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_FIRMWARE_MANAGEMENT_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 && (!package_version || !package_version_name)) { > + 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); > +} > + > +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("%s: Unable to open the firmware image for writing\n", > + __func__); > + status = EFI_DEVICE_ERROR; > + goto back; > + } > + > + ret = smh_write(fd, (void *)image, image_size); > + if (ret == -1) { > + printf("%s: Error writing to the firmware image!", __func__); > + smh_close(fd); > + status = EFI_DEVICE_ERROR; > + goto back; > + } > + > + printf("%s: Done writing the firmware image file\n", __func__); > + 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; > +} > -- > 2.17.1 >
diff --git a/board/emulation/qemu-arm/Kconfig b/board/emulation/qemu-arm/Kconfig index 02ae4d9884..1ef2a27539 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 + +config EFI_FIRMWARE_MANAGEMENT_PROTOCOL + bool "EFI Firmware Management protocol for Qemu arm64 platform" + depends on EFI_CAPSULE_UPDATE && EFI_CAPSULE_UPDATE_FIRMWARE + 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..17caa59786 --- /dev/null +++ b/board/emulation/qemu-arm/qemu_efi_fmp.c @@ -0,0 +1,173 @@ +// 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" + +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_FIRMWARE_MANAGEMENT_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 && (!package_version || !package_version_name)) { + 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); +} + +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("%s: Unable to open the firmware image for writing\n", + __func__); + status = EFI_DEVICE_ERROR; + goto back; + } + + ret = smh_write(fd, (void *)image, image_size); + if (ret == -1) { + printf("%s: Error writing to the firmware image!", __func__); + smh_close(fd); + status = EFI_DEVICE_ERROR; + goto back; + } + + printf("%s: Done writing the firmware image file\n", __func__); + 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; +}
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. 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 | 173 ++++++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 board/emulation/qemu-arm/qemu_efi_fmp.c