From patchwork Mon Mar 23 07:11:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 244131 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Mon, 23 Mar 2020 12:41:58 +0530 Subject: [RFC PATCH 1/4] efidebug: capsule: Add a command to update capsule on disk In-Reply-To: <20200323071201.5992-1-sughosh.ganu@linaro.org> References: <20200323071201.5992-1-sughosh.ganu@linaro.org> Message-ID: <20200323071201.5992-2-sughosh.ganu@linaro.org> Add a efidebug subcommand to initiate a firmware update using the efi firmware management protocol(fmp) set_image routine. The firmware update can be initiated through 'efidebug capsule disk-update' This would locate the efi capsule file on the efi system partition, and call the platform's set_image fmp routine to initiate the firmware update. Signed-off-by: Sughosh Ganu --- cmd/efidebug.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 4a7661d0ac..fd8366dc90 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -77,6 +77,16 @@ static int do_efi_capsule_update(cmd_tbl_t *cmdtp, int flag, return CMD_RET_SUCCESS; } +static int do_efi_capsule_on_disk_update(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_status_t ret; + + ret = efi_launch_capsules(); + + return ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE; +} + /** * do_efi_capsule_show() - show capsule information * @@ -205,6 +215,8 @@ static cmd_tbl_t cmd_efidebug_capsule_sub[] = { "", ""), U_BOOT_CMD_MKENT(show, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_show, "", ""), + U_BOOT_CMD_MKENT(disk-update, 0, 0, do_efi_capsule_on_disk_update, + "", ""), U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res, "", ""), }; @@ -1387,6 +1399,8 @@ static char efidebug_help_text[] = #ifdef CONFIG_EFI_CAPSULE_UPDATE "efidebug capsule update [-v] \n" " - process a capsule\n" + "efidebug capsule disk-update\n" + " - update a capsule from disk\n" "efidebug capsule show \n" " - show capsule information\n" "efidebug capsule result []\n" From patchwork Mon Mar 23 07:11:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 244132 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Mon, 23 Mar 2020 12:41:59 +0530 Subject: [RFC PATCH 2/4] semihosting: Change semihosting file operation functions into global symbols In-Reply-To: <20200323071201.5992-1-sughosh.ganu@linaro.org> References: <20200323071201.5992-1-sughosh.ganu@linaro.org> Message-ID: <20200323071201.5992-3-sughosh.ganu@linaro.org> Change the semihosting file operation functions into external symbols so that they can be called from outside the file. These functions would be required to be called for implementing firmware update functionality for the qemu arm64 platform. Signed-off-by: Sughosh Ganu --- arch/arm/lib/semihosting.c | 7 ++++--- include/semihosting.h | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 include/semihosting.h diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c index 2658026cf4..3aeda1303a 100644 --- a/arch/arm/lib/semihosting.c +++ b/arch/arm/lib/semihosting.c @@ -13,6 +13,7 @@ */ #include #include +#include #define SYSOPEN 0x01 #define SYSCLOSE 0x02 @@ -43,7 +44,7 @@ static noinline long smh_trap(unsigned int sysnum, void *addr) * Open a file on the host. Mode is "r" or "rb" currently. Returns a file * descriptor or -1 on error. */ -static long smh_open(const char *fname, char *modestr) +long smh_open(const char *fname, char *modestr) { long fd; unsigned long mode; @@ -82,7 +83,7 @@ static long smh_open(const char *fname, char *modestr) /* * Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure */ -static long smh_read(long fd, void *memp, size_t len) +long smh_read(long fd, void *memp, size_t len) { long ret; struct smh_read_s { @@ -116,7 +117,7 @@ static long smh_read(long fd, void *memp, size_t len) /* * Close the file using the file descriptor */ -static long smh_close(long fd) +long smh_close(long fd) { long ret; diff --git a/include/semihosting.h b/include/semihosting.h new file mode 100644 index 0000000000..f1bf419275 --- /dev/null +++ b/include/semihosting.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020, Linaro Limited + */ + +#if !defined _SEMIHOSTING_H_ +#define _SEMIHOSTING_H_ + +long smh_open(const char *fname, char *modestr); +long smh_read(long fd, void *memp, size_t len); +long smh_close(long fd); + +#endif /* _SEMIHOSTING_H_ */ From patchwork Mon Mar 23 07:12:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 244133 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Mon, 23 Mar 2020 12:42:00 +0530 Subject: [RFC PATCH 3/4] semihosting: Add support for writing to a file In-Reply-To: <20200323071201.5992-1-sughosh.ganu@linaro.org> References: <20200323071201.5992-1-sughosh.ganu@linaro.org> Message-ID: <20200323071201.5992-4-sughosh.ganu@linaro.org> Add a function to enable writing to a file. Currently, support is added for writing to a binary file. This would be used for implementing the firmware update functionality for the qemu arm64 platform. Signed-off-by: Sughosh Ganu --- arch/arm/lib/semihosting.c | 41 ++++++++++++++++++++++++++++++++++++-- include/semihosting.h | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c index 3aeda1303a..08181132d1 100644 --- a/arch/arm/lib/semihosting.c +++ b/arch/arm/lib/semihosting.c @@ -17,11 +17,18 @@ #define SYSOPEN 0x01 #define SYSCLOSE 0x02 +#define SYSWRITE 0x5 #define SYSREAD 0x06 #define SYSFLEN 0x0C -#define MODE_READ 0x0 -#define MODE_READBIN 0x1 +#define MODE_READ 0x0 +#define MODE_READBIN 0x1 +#define MODE_READPLUS 0x2 +#define MODE_READPLUSBIN 0x3 +#define MODE_WRITE 0x4 +#define MODE_WRITEBIN 0x5 +#define MODE_WRITEPLUS 0x6 +#define MODE_WRITEPLUSBIN 0x7 /* * Call the handler @@ -61,6 +68,8 @@ long smh_open(const char *fname, char *modestr) mode = MODE_READ; } else if (!(strcmp(modestr, "rb"))) { mode = MODE_READBIN; + } else if (!strcmp(modestr, "w+b")) { + mode = MODE_WRITEPLUSBIN; } else { printf("%s: ERROR mode \'%s\' not supported\n", __func__, modestr); @@ -114,6 +123,34 @@ long smh_read(long fd, void *memp, size_t len) return 0; } +/* + * Write 'len' bytes into the file referenced by the fd. Returns 0 on success, else + * a negavite value for failure + */ +long smh_write(long fd, void *memp, size_t len) +{ + long ret; + struct smh_write_s { + long fd; + void *memp; + size_t len; + } write; + + debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len); + + write.fd = fd; + write.memp = memp; + write.len = len; + + ret = smh_trap(SYSWRITE, &write); + + if (ret > 0) + printf("%s: ERROR ret %ld, fd %ld, len %zu, memp %p\n", + __func__, ret, fd, len, memp); + + return ret == 0 ? 0 : -1; +} + /* * Close the file using the file descriptor */ diff --git a/include/semihosting.h b/include/semihosting.h index f1bf419275..fa5cecddf2 100644 --- a/include/semihosting.h +++ b/include/semihosting.h @@ -8,6 +8,7 @@ long smh_open(const char *fname, char *modestr); long smh_read(long fd, void *memp, size_t len); +long smh_write(long fd, void *memp, size_t len); long smh_close(long fd); #endif /* _SEMIHOSTING_H_ */ From patchwork Mon Mar 23 07:12:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 244134 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Mon, 23 Mar 2020 12:42:01 +0530 Subject: [RFC PATCH 4/4] qemu: arm64: Add support for efi firmware management protocol routines In-Reply-To: <20200323071201.5992-1-sughosh.ganu@linaro.org> References: <20200323071201.5992-1-sughosh.ganu@linaro.org> Message-ID: <20200323071201.5992-5-sughosh.ganu@linaro.org> 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 --- 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 + 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 +#include +#include +#include +#include +#include + +#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; +}