From 73981390dfea84b2861d285b2d1b2fd33a84b665 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 21 Oct 2022 18:15:54 +0530 Subject: dt/bindings: Add bindings for GPT based FWU Metadata storage device Add bindings needed for accessing the FWU metadata partitions. These include the compatible string which point to the access method and the actual device which stores the FWU metadata. The current patch adds basic bindings needed for accessing the metadata structure on GPT partitioned block devices. Signed-off-by: Sughosh Ganu Reviewed-by: Heinrich Schuchardt Acked-by: Etienne Carriere Reviewed-by: Ilias Apalodimas --- .../firmware/fwu-mdata-gpt.yaml | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 doc/device-tree-bindings/firmware/fwu-mdata-gpt.yaml (limited to 'doc') diff --git a/doc/device-tree-bindings/firmware/fwu-mdata-gpt.yaml b/doc/device-tree-bindings/firmware/fwu-mdata-gpt.yaml new file mode 100644 index 00000000000..0735191ff15 --- /dev/null +++ b/doc/device-tree-bindings/firmware/fwu-mdata-gpt.yaml @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/firmware/fwu-mdata-gpt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: FWU metadata on device with GPT partitioned layout + +maintainers: + - Sughosh Ganu + +properties: + compatible: + items: + - const: u-boot,fwu-mdata-gpt + + fwu-mdata-store: + maxItems: 1 + description: Phandle of the device which contains the FWU medatata partition. + +required: + - compatible + - fwu-mdata-store + +additionalProperties: false + +examples: + - | + fwu-mdata { + compatible = "u-boot,fwu-mdata-gpt"; + fwu-mdata-store = <&sdmmc1>; + }; -- cgit v1.3.1 From e68c03be46ce9bf409a2a9ad761a247d8640c89a Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 21 Oct 2022 18:16:04 +0530 Subject: FWU: cmd: Add a command to read FWU metadata Add a command to read the metadata as specified in the FWU specification and print the fields of the metadata. Signed-off-by: Sughosh Ganu Reviewed-by: Ilias Apalodimas Reviewed-by: Etienne Carriere --- cmd/Kconfig | 6 ++++ cmd/Makefile | 1 + cmd/fwu_mdata.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/fwu_mdata.rst | 43 ++++++++++++++++++++++++ doc/usage/index.rst | 1 + 5 files changed, 130 insertions(+) create mode 100644 cmd/fwu_mdata.c create mode 100644 doc/usage/cmd/fwu_mdata.rst (limited to 'doc') diff --git a/cmd/Kconfig b/cmd/Kconfig index 3f6bc70d43a..105406496ec 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -162,6 +162,12 @@ config CMD_CPU internal name) and clock frequency. Other information may be available depending on the CPU driver. +config CMD_FWU_METADATA + bool "fwu metadata read" + depends on FWU_MULTI_BANK_UPDATE + help + Command to read the metadata and dump it's contents + config CMD_LICENSE bool "license" select BUILD_BIN2C diff --git a/cmd/Makefile b/cmd/Makefile index ca9ed1054d7..2444d116c07 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_CMD_FPGA) += fpga.o obj-$(CONFIG_CMD_FPGAD) += fpgad.o obj-$(CONFIG_CMD_FS_GENERIC) += fs.o obj-$(CONFIG_CMD_FUSE) += fuse.o +obj-$(CONFIG_CMD_FWU_METADATA) += fwu_mdata.o obj-$(CONFIG_CMD_GETTIME) += gettime.o obj-$(CONFIG_CMD_GPIO) += gpio.o obj-$(CONFIG_CMD_HVC) += smccc.o diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c new file mode 100644 index 00000000000..f04af27de63 --- /dev/null +++ b/cmd/fwu_mdata.c @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2022, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static void print_mdata(struct fwu_mdata *mdata) +{ + int i, j; + struct fwu_image_entry *img_entry; + struct fwu_image_bank_info *img_info; + + printf("\tFWU Metadata\n"); + printf("crc32: %#x\n", mdata->crc32); + printf("version: %#x\n", mdata->version); + printf("active_index: %#x\n", mdata->active_index); + printf("previous_active_index: %#x\n", mdata->previous_active_index); + + printf("\tImage Info\n"); + for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) { + img_entry = &mdata->img_entry[i]; + printf("\nImage Type Guid: %pUL\n", + &img_entry->image_type_uuid); + printf("Location Guid: %pUL\n", &img_entry->location_uuid); + for (j = 0; j < CONFIG_FWU_NUM_BANKS; j++) { + img_info = &img_entry->img_bank_info[j]; + printf("Image Guid: %pUL\n", &img_info->image_uuid); + printf("Image Acceptance: %s\n", + img_info->accepted == 0x1 ? "yes" : "no"); + } + } +} + +int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag, + int argc, char * const argv[]) +{ + struct udevice *dev; + int ret = CMD_RET_SUCCESS, res; + struct fwu_mdata mdata = { 0 }; + + if (uclass_get_device(UCLASS_FWU_MDATA, 0, &dev) || !dev) { + log_err("Unable to get FWU metadata device\n"); + return CMD_RET_FAILURE; + } + + res = fwu_check_mdata_validity(); + if (res < 0) { + log_err("FWU Metadata check failed\n"); + ret = CMD_RET_FAILURE; + goto out; + } + + res = fwu_get_mdata(dev, &mdata); + if (res < 0) { + log_err("Unable to get valid FWU metadata\n"); + ret = CMD_RET_FAILURE; + goto out; + } + + print_mdata(&mdata); + +out: + return ret; +} + +U_BOOT_CMD( + fwu_mdata_read, 1, 1, do_fwu_mdata_read, + "Read and print FWU metadata", + "" +); diff --git a/doc/usage/cmd/fwu_mdata.rst b/doc/usage/cmd/fwu_mdata.rst new file mode 100644 index 00000000000..ea3c22724a3 --- /dev/null +++ b/doc/usage/cmd/fwu_mdata.rst @@ -0,0 +1,43 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +fwu_mdata_read command +====================== + +Synopsis +-------- + +:: + + fwu_mdata_read + +Description +----------- + +The fwu_mdata_read command is used to read the FWU metadata +structure. The command prints out information about the current active +bank, the previous active bank, image GUIDs, image acceptance etc. + +The output may look like: + +:: + + => fwu_mdata_read + FWU Metadata + crc32: 0xec4fb997 + version: 0x1 + active_index: 0x0 + previous_active_index: 0x1 + Image Info + + Image Type Guid: 19D5DF83-11B0-457B-BE2C-7559C13142A5 + Location Guid: 49272BEB-8DD8-46DF-8D75-356C65EFF417 + Image Guid: D57428CC-BB9A-42E0-AA36-3F5A132059C7 + Image Acceptance: yes + Image Guid: 2BE37D6D-8281-4938-BD7B-9A5BBF80869F + Image Acceptance: yes + +Configuration +------------- + +To use the fwu_mdata_read command, CONFIG_CMD_FWU_METADATA needs to be +enabled. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index c601d3576d5..df50746c349 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -50,6 +50,7 @@ Shell commands cmd/fdt cmd/font cmd/for + cmd/fwu_mdata cmd/gpio cmd/load cmd/loadm -- cgit v1.3.1 From 6da9271af112a3133748b624c27e2ff09b6ee842 Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 21 Oct 2022 18:16:06 +0530 Subject: mkeficapsule: Add support for generating empty capsules The Dependable Boot specification[1] describes the structure of the firmware accept and revert capsules. These are empty capsules which are used for signalling the acceptance or rejection of the updated firmware by the OS. Add support for generating these empty capsules. [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf Signed-off-by: Sughosh Ganu Acked-by: Ilias Apalodimas Acked-by: Etienne Carriere --- doc/mkeficapsule.1 | 29 ++++++++++++---- tools/eficapsule.h | 8 +++++ tools/mkeficapsule.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 119 insertions(+), 14 deletions(-) (limited to 'doc') diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 09bdc242957..77ca061efdc 100644 --- a/doc/mkeficapsule.1 +++ b/doc/mkeficapsule.1 @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot .SH SYNOPSIS .B mkeficapsule -.RI [ options "] " image-blob " " capsule-file +.RI [ options ] " " [ image-blob ] " " capsule-file .SH "DESCRIPTION" .B mkeficapsule @@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key. In this case, the update will be authenticated by verifying the signature before applying. +Additionally, an empty capsule file can be generated for acceptance or +rejection of firmware images by a governing component like an Operating +System. The empty capsules do not require an image-blob input file. + + .B mkeficapsule -takes any type of image files, including: +takes any type of image files when generating non empty capsules, including: .TP .I raw image format is a single binary blob of any type of firmware. @@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file. This type of image file can be generated by .BR mkimage . -.PP -If you want to use other types than above two, you should explicitly -specify a guid for the FMP driver. - .SH "OPTIONS" + .TP .BI "-g\fR,\fB --guid " guid-string Specify guid for image blob type. The format is: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx The first three elements are in little endian, while the rest -is in big endian. +is in big endian. The option must be specified for all non empty and +image acceptance capsules .TP .BI "-i\fR,\fB --index " index @@ -57,6 +60,18 @@ Specify an image index .BI "-I\fR,\fB --instance " instance Specify a hardware instance +.PP +For generation of firmware accept empty capsule +.BR --guid +is mandatory +.TP +.BI "-A\fR,\fB --fw-accept " +Generate a firmware acceptance empty capsule + +.TP +.BI "-R\fR,\fB --fw-revert " +Generate a firmware revert empty capsule + .TP .BR -h ", " --help Print a help message diff --git a/tools/eficapsule.h b/tools/eficapsule.h index d63b8314432..072a4b5598b 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -41,6 +41,14 @@ typedef struct { EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \ 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7) +#define FW_ACCEPT_OS_GUID \ + EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \ + 0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8) + +#define FW_REVERT_OS_GUID \ + EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \ + 0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0) + /* flags */ #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 5f74d23b9e3..25bfb39e5b3 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,7 +29,13 @@ static const char *tool_name = "mkeficapsule"; efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; -static const char *opts_short = "g:i:I:v:p:c:m:dh"; +static const char *opts_short = "g:i:I:v:p:c:m:dhAR"; + +enum { + CAPSULE_NORMAL_BLOB = 0, + CAPSULE_ACCEPT, + CAPSULE_REVERT, +} capsule_type; static struct option options[] = { {"guid", required_argument, NULL, 'g'}, @@ -39,6 +45,8 @@ static struct option options[] = { {"certificate", required_argument, NULL, 'c'}, {"monotonic-count", required_argument, NULL, 'm'}, {"dump-sig", no_argument, NULL, 'd'}, + {"fw-accept", no_argument, NULL, 'A'}, + {"fw-revert", no_argument, NULL, 'R'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -55,6 +63,8 @@ static void print_usage(void) "\t-c, --certificate signer's certificate file\n" "\t-m, --monotonic-count monotonic count\n" "\t-d, --dump_sig dump signature (*.p7)\n" + "\t-A, --fw-accept firmware accept capsule, requires GUID, no image blob\n" + "\t-R, --fw-revert firmware revert capsule, takes no GUID, no image blob\n" "\t-h, --help print a help message\n", tool_name); } @@ -564,6 +574,49 @@ void convert_uuid_to_guid(unsigned char *buf) buf[7] = c; } +static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept) +{ + struct efi_capsule_header header = { 0 }; + FILE *f = NULL; + int ret = -1; + efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID; + efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID; + efi_guid_t capsule_guid; + + f = fopen(path, "w"); + if (!f) { + fprintf(stderr, "cannot open %s\n", path); + goto err; + } + + capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid; + + memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t)); + header.header_size = sizeof(header); + header.flags = 0; + + header.capsule_image_size = fw_accept ? + sizeof(header) + sizeof(efi_guid_t) : sizeof(header); + + if (write_capsule_file(f, &header, sizeof(header), + "Capsule header")) + goto err; + + if (fw_accept) { + if (write_capsule_file(f, guid, sizeof(*guid), + "FW Accept Capsule Payload")) + goto err; + } + + ret = 0; + +err: + if (f) + fclose(f); + + return ret; +} + /** * main - main entry function of mkeficapsule * @argc: Number of arguments @@ -592,6 +645,7 @@ int main(int argc, char **argv) privkey_file = NULL; cert_file = NULL; dump_sig = 0; + capsule_type = CAPSULE_NORMAL_BLOB; for (;;) { c = getopt_long(argc, argv, opts_short, options, &idx); if (c == -1) @@ -639,22 +693,50 @@ int main(int argc, char **argv) case 'd': dump_sig = 1; break; - case 'h': + case 'A': + if (capsule_type) { + fprintf(stderr, + "Select either of Accept or Revert capsule generation\n"); + exit(1); + } + capsule_type = CAPSULE_ACCEPT; + break; + case 'R': + if (capsule_type) { + fprintf(stderr, + "Select either of Accept or Revert capsule generation\n"); + exit(1); + } + capsule_type = CAPSULE_REVERT; + break; + default: print_usage(); exit(EXIT_SUCCESS); } } /* check necessary parameters */ - if ((argc != optind + 2) || !guid || - ((privkey_file && !cert_file) || - (!privkey_file && cert_file))) { + if ((capsule_type == CAPSULE_NORMAL_BLOB && + ((argc != optind + 2) || !guid || + ((privkey_file && !cert_file) || + (!privkey_file && cert_file)))) || + (capsule_type != CAPSULE_NORMAL_BLOB && + ((argc != optind + 1) || + ((capsule_type == CAPSULE_ACCEPT) && !guid) || + ((capsule_type == CAPSULE_REVERT) && guid)))) { print_usage(); exit(EXIT_FAILURE); } - if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance, - mcount, privkey_file, cert_file) < 0) { + if (capsule_type != CAPSULE_NORMAL_BLOB) { + if (create_empty_capsule(argv[argc - 1], guid, + capsule_type == CAPSULE_ACCEPT) < 0) { + fprintf(stderr, "Creating empty capsule failed\n"); + exit(EXIT_FAILURE); + } + } else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, + index, instance, mcount, privkey_file, + cert_file) < 0) { fprintf(stderr, "Creating firmware capsule failed\n"); exit(EXIT_FAILURE); } -- cgit v1.3.1 From f65ee99b9d574a5b7dcf1322eb13f0b79860bd6c Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 21 Oct 2022 18:16:07 +0530 Subject: mkeficapsule: Add support for setting OEM flags in capsule header Add support for setting OEM flags in the capsule header. As per the UEFI specification, bits 0-15 of the flags member of the capsule header can be defined per capsule GUID. The oemflags will be used for the FWU Multi Bank update feature, as specified by the Dependable Boot specification[1]. Bit 15 of the flags member will be used to determine if the acceptance/rejection of the updated images is to be done by the firmware or an external component like the OS. [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf Signed-off-by: Sughosh Ganu Reviewed-by: Ilias Apalodimas Acked-by: Etienne Carriere --- doc/mkeficapsule.1 | 4 ++++ tools/mkeficapsule.c | 22 +++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'doc') diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 77ca061efdc..6fb2dd0810d 100644 --- a/doc/mkeficapsule.1 +++ b/doc/mkeficapsule.1 @@ -72,6 +72,10 @@ Generate a firmware acceptance empty capsule .BI "-R\fR,\fB --fw-revert " Generate a firmware revert empty capsule +.TP +.BI "-o\fR,\fB --capoemflag " +Capsule OEM flag, value between 0x0000 to 0xffff + .TP .BR -h ", " --help Print a help message diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 25bfb39e5b3..b71537beee0 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,7 +29,7 @@ static const char *tool_name = "mkeficapsule"; efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; -static const char *opts_short = "g:i:I:v:p:c:m:dhAR"; +static const char *opts_short = "g:i:I:v:p:c:m:o:dhAR"; enum { CAPSULE_NORMAL_BLOB = 0, @@ -47,6 +47,7 @@ static struct option options[] = { {"dump-sig", no_argument, NULL, 'd'}, {"fw-accept", no_argument, NULL, 'A'}, {"fw-revert", no_argument, NULL, 'R'}, + {"capoemflag", required_argument, NULL, 'o'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -65,6 +66,7 @@ static void print_usage(void) "\t-d, --dump_sig dump signature (*.p7)\n" "\t-A, --fw-accept firmware accept capsule, requires GUID, no image blob\n" "\t-R, --fw-revert firmware revert capsule, takes no GUID, no image blob\n" + "\t-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n" "\t-h, --help print a help message\n", tool_name); } @@ -387,6 +389,7 @@ static void free_sig_data(struct auth_context *ctx) * @mcount: Monotonic count in authentication information * @private_file: Path to a private key file * @cert_file: Path to a certificate file + * @oemflags: Capsule OEM Flags, bits 0-15 * * This function actually does the job of creating an uefi capsule file. * All the arguments must be supplied. @@ -399,7 +402,8 @@ static void free_sig_data(struct auth_context *ctx) */ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, unsigned long index, unsigned long instance, - uint64_t mcount, char *privkey_file, char *cert_file) + uint64_t mcount, char *privkey_file, char *cert_file, + uint16_t oemflags) { struct efi_capsule_header header; struct efi_firmware_management_capsule_header capsule; @@ -464,6 +468,8 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, header.header_size = sizeof(header); /* TODO: The current implementation ignores flags */ header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET; + if (oemflags) + header.flags |= oemflags; header.capsule_image_size = sizeof(header) + sizeof(capsule) + sizeof(uint64_t) + sizeof(image) @@ -635,6 +641,7 @@ int main(int argc, char **argv) unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount; + unsigned long oemflags; char *privkey_file, *cert_file; int c, idx; @@ -646,6 +653,7 @@ int main(int argc, char **argv) cert_file = NULL; dump_sig = 0; capsule_type = CAPSULE_NORMAL_BLOB; + oemflags = 0; for (;;) { c = getopt_long(argc, argv, opts_short, options, &idx); if (c == -1) @@ -709,6 +717,14 @@ int main(int argc, char **argv) } capsule_type = CAPSULE_REVERT; break; + case 'o': + oemflags = strtoul(optarg, NULL, 0); + if (oemflags > 0xffff) { + fprintf(stderr, + "oemflags must be between 0x0 and 0xffff\n"); + exit(1); + } + break; default: print_usage(); exit(EXIT_SUCCESS); @@ -736,7 +752,7 @@ int main(int argc, char **argv) } } else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance, mcount, privkey_file, - cert_file) < 0) { + cert_file, (uint16_t)oemflags) < 0) { fprintf(stderr, "Creating firmware capsule failed\n"); exit(EXIT_FAILURE); } -- cgit v1.3.1 From 75f11c3bfdcfbadad0265eda74c372e52423ae4c Mon Sep 17 00:00:00 2001 From: Sughosh Ganu Date: Fri, 21 Oct 2022 18:16:08 +0530 Subject: FWU: doc: Add documentation for the FWU feature Add documentation for the FWU Multi Bank Update feature. The document describes the steps needed for setting up the platform for the feature, as well as steps for enabling the feature on the platform. Signed-off-by: Sughosh Ganu Acked-by: Etienne Carriere Acked-by: Ilias Apalodimas --- doc/develop/uefi/fwu_updates.rst | 184 +++++++++++++++++++++++++++++++++++++++ doc/develop/uefi/index.rst | 1 + doc/develop/uefi/uefi.rst | 12 +++ 3 files changed, 197 insertions(+) create mode 100644 doc/develop/uefi/fwu_updates.rst (limited to 'doc') diff --git a/doc/develop/uefi/fwu_updates.rst b/doc/develop/uefi/fwu_updates.rst new file mode 100644 index 00000000000..72c850a7908 --- /dev/null +++ b/doc/develop/uefi/fwu_updates.rst @@ -0,0 +1,184 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (c) 2022 Linaro Limited + +FWU Multi Bank Updates in U-Boot +================================ + +The FWU Multi Bank Update feature implements the firmware update +mechanism described in the PSA Firmware Update for A-profile Arm +Architecture specification [1]. Certain aspects of the Dependable +Boot specification [2] are also implemented. The feature provides a +mechanism to have multiple banks of updatable firmware images and for +updating the firmware images on the non-booted bank. On a successful +update, the platform boots from the updated bank on subsequent +boot. The UEFI capsule-on-disk update feature is used for performing +the actual updates of the updatable firmware images. + +The bookkeeping of the updatable images is done through a structure +called metadata. Currently, the FWU metadata supports identification +of images based on image GUIDs stored on a GPT partitioned storage +media. There are plans to extend the metadata structure for non GPT +partitioned devices as well. + +Accessing the FWU metadata is done through generic API's which are +defined in a driver which complies with the U-Boot's driver model. A +new uclass UCLASS_FWU_MDATA has been added for accessing the FWU +metadata. Individual drivers can be added based on the type of storage +media, and its partitioning method. Details of the storage device +containing the FWU metadata partitions are specified through a U-Boot +specific device tree property `fwu-mdata-store`. Please refer to +U-Boot `doc `__ +for the device tree bindings. + +Enabling the FWU Multi Bank Update feature +------------------------------------------ + +The feature can be enabled by specifying the following configs:: + + CONFIG_EFI_CAPSULE_ON_DISK=y + CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y + CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y + + CONFIG_FWU_MULTI_BANK_UPDATE=y + CONFIG_FWU_MDATA=y + CONFIG_FWU_MDATA_GPT_BLK=y + CONFIG_FWU_NUM_BANKS= + CONFIG_FWU_NUM_IMAGES_PER_BANK= + +in the .config file + +By enabling the CONFIG_CMD_FWU_METADATA config option, the +fwu_mdata_read command can be used to check the current state of the +FWU metadata structure. + +The first group of configuration settings enable the UEFI +capsule-on-disk update functionality. The second group of configs +enable the FWU Multi Bank Update functionality. Please refer to the +section :ref:`uefi_capsule_update_ref` for more details on generation +of the UEFI capsule. + +Setting up the device for GPT partitioned storage +------------------------------------------------- + +Before enabling the functionality in U-Boot, a GPT partitioned storage +device is required. Assuming a GPT partitioned storage device, the +storage media needs to be partitioned with the correct number of +partitions, given the number of banks and number of images per bank +that the platform is going to support. Each updatable firmware image +will be stored on a separate partition. In addition, the two copies +of the FWU metadata will be stored on two separate partitions. These +partitions need to be created at the time of the platform's +provisioning. + +As an example, a platform supporting two banks with each bank +containing three images would need to have 2 * 3 = 6 partitions plus +the two metadata partitions, or 8 partitions. In addition the storage +media can have additional partitions of non-updatable images, like the +EFI System Partition(ESP), a partition for the root file system +etc. An example list of images on the storage medium would be + +* FWU metadata 1 +* U-Boot 1 +* OP-TEE 1 +* FWU metadata 2 +* OP-TEE 2 +* U-Boot 2 +* ESP +* rootfs + +When generating the partitions, a few aspects need to be taken care +of. Each GPT partition entry in the GPT header has two GUIDs:: + +* PartitionTypeGUID +* UniquePartitionGUID + +The PartitionTypeGUID value should correspond to the +``image_type_uuid`` field of the FWU metadata. This field is used to +identify a given type of updatable firmware image, e.g. U-Boot, +OP-TEE, FIP etc. This GUID should also be used for specifying the +`--guid` parameter when generating the capsule. + +The UniquePartitionGUID value should correspond to the ``image_uuid`` +field in the FWU metadata. This GUID is used to identify images of a +given image type in different banks. + +The FWU specification defines the GUID value to be used for the +metadata partitions. This would be the PartitionTypeGUID for the +metadata partitions. Similarly, the UEFI specification defines the ESP +GUID to be be used. + +When generating the metadata, the ``image_type_uuid`` and the +``image_uuid`` values should match the *PartitionTypeGUID* and the +*UniquePartitionGUID* values respectively. + +Performing the Update +--------------------- + +Once the storage media has been partitioned and populated with the +metadata partitions, the UEFI capsule-on-disk update functionality can +be used for performing the update. Refer to the section +:ref:`uefi_capsule_update_ref` for details on how the update can be +invoked. + +On a successful update, the FWU metadata gets updated to reflect the +bank from which the platform would be booting on subsequent boot. + +Based on the value of bit15 of the Flags member of the capsule header, +the updated images would either be accepted by the U-Boot's UEFI +implementation, or by the Operating System. If the Operating System is +accepting the firmware images, it does so by generating an empty +*accept* capsule. The Operating System can also reject the updated +firmware by generating a *revert* capsule. The empty capsule can be +applied by using the exact same procedure used for performing the +capsule-on-disk update. + +The task of accepting the different firmware images, post an update +may be done by multiple, separate components in the Operating +System. To help identify the firmware image that is being accepted, +the accept capsule passes the image GUID of the firmware image being +accepted. The relevant code in U-Boot then sets the Accept bit of the +corresponding firmware image for which the accept capsule was +found. Only when all the firmware components in a bank have been +accepted does the platform transition from trial state to regular +state. + +The revert capsule on the other hand does not pass any image GUID, +since reverting any image of the bank has the same result of the +platform booting from the other bank on subsequent boot. + +In the scenario that bit15 of the Flags member of the capsule header +has not been set, the images being updated are accepted by the +U-Boot's UEFI firmware implementation by default, on successful +update of the image. + +Generating an empty capsule +--------------------------- + +The empty capsule can be generated using the mkeficapsule utility. To +build the tool, enable:: + + CONFIG_TOOLS_MKEFICAPSULE=y + +Run the following commands to generate the accept/revert capsules:: + +.. code-block:: bash + + $ ./tools/mkeficapsule \ + [--fw-accept --guid ] | \ + [--fw-revert] \ + + +Some examples of using the mkeficapsule tool for generation of the +empty capsule would be:: + +.. code-block:: bash + + $ ./tools/mkeficapsule --fw-accept --guid \ + + $ ./tools/mkeficapsule --fw-revert + +Links +----- + +* [1] https://developer.arm.com/documentation/den0118/a/ - FWU Specification +* [2] https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf - Dependable Boot Specification diff --git a/doc/develop/uefi/index.rst b/doc/develop/uefi/index.rst index 7e65dbc5d5e..e26b1fbe05c 100644 --- a/doc/develop/uefi/index.rst +++ b/doc/develop/uefi/index.rst @@ -13,3 +13,4 @@ can be run an UEFI payload. uefi.rst u-boot_on_efi.rst iscsi.rst + fwu_updates.rst diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index cd847069530..e0835beba41 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -277,6 +277,8 @@ Enable ``CONFIG_OPTEE``, ``CONFIG_CMD_OPTEE_RPMB`` and ``CONFIG_EFI_MM_COMM_TEE` [1] https://optee.readthedocs.io/en/latest/building/efi_vars/stmm.html +.. _uefi_capsule_update_ref: + Enabling UEFI Capsule Update feature ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -377,6 +379,16 @@ following command:: dfu list +When the FWU Multi Bank Update feature is enabled on the platform, the +image index is used only to identify the image index with the image +GUID. The image index would not correspond to the dfu alt number. This +is because the FWU feature supports multiple partitions(banks) of +updatable images, and the actual dfu alt number to which the image is +to be written to is determined at runtime, based on the value of the +update bank to which the image is to be written. For more information +on the FWU Multi Bank Update feature, please refer `doc +`__. + When using the FMP for FIT images, the image index value needs to be set to 1. -- cgit v1.3.1