diff options
author | Tom Rini <trini@konsulko.com> | 2024-05-24 13:42:07 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-05-24 13:42:07 -0600 |
commit | 7e52d6ccfb76e2afc2d183b357abe2a2e2f948cf (patch) | |
tree | 13766eee290b99a1bb0254235841a0e4c492d62f /tools | |
parent | 6b9ae5789e9beef7fb78893c7c831e2b31b705f6 (diff) | |
parent | e32c15d6041e9298673c75b26cc6af1266046dc5 (diff) | |
download | u-boot-7e52d6ccfb76e2afc2d183b357abe2a2e2f948cf.tar.gz u-boot-7e52d6ccfb76e2afc2d183b357abe2a2e2f948cf.tar.bz2 u-boot-7e52d6ccfb76e2afc2d183b357abe2a2e2f948cf.zip |
Merge patch series "FWU: Add support for FWU metadata version 2"
Sughosh Ganu <sughosh.ganu@linaro.org> says:
The following patch series adds support for version 2 of the FWU
metadata. The version 2 metadata structure is defined in the latest
revision of the FWU specification [1].
The earlier versions of these patches were migrating to a version 2
only support in U-Boot, similar to TF-A. However, based on feedback
from ST [2], this series has been updated to support both versions. A
platform would still be needed to enable one of the two versions of
metadata through a config symbol.
TF-A has code which reads the FWU metadata and boots the platform from
the active partition. TF-A has decided to migrate the FWU code to a
version 2 only support. These changes have been merged in upstream
TF-A.
These changes have been tested on the ST DK2 board, which uses the GPT
based partitioning scheme. Both V1 and V2 metadata versions have been
tested on the DK2 board.
These changes need to be tested on platforms with MTD partitioned
storage devices.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/mkfwumdata.c | 235 |
1 files changed, 197 insertions, 38 deletions
diff --git a/tools/mkfwumdata.c b/tools/mkfwumdata.c index 9732a8ddc5..fbc2067bc1 100644 --- a/tools/mkfwumdata.c +++ b/tools/mkfwumdata.c @@ -10,28 +10,35 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> -#include <u-boot/crc.h> #include <unistd.h> +#include <generated/autoconf.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <u-boot/crc.h> #include <uuid/uuid.h> -/* This will dynamically allocate the fwu_mdata */ -#define CONFIG_FWU_NUM_BANKS 0 -#define CONFIG_FWU_NUM_IMAGES_PER_BANK 0 - -/* Since we can not include fwu.h, redefine version here. */ -#define FWU_MDATA_VERSION 1 - typedef uint8_t u8; typedef int16_t s16; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; -#include <fwu_mdata.h> +#undef CONFIG_FWU_NUM_BANKS +#undef CONFIG_FWU_NUM_IMAGES_PER_BANK -/* TODO: Endianness conversion may be required for some arch. */ +/* This will dynamically allocate the fwu_mdata */ +#define CONFIG_FWU_NUM_BANKS 0 +#define CONFIG_FWU_NUM_IMAGES_PER_BANK 0 + +/* version 2 supports maximum of 4 banks */ +#define MAX_BANKS_V2 4 + +#define BANK_INVALID (u8)0xFF +#define BANK_ACCEPTED (u8)0xFC -static const char *opts_short = "b:i:a:p:gh"; +#include <fwu_mdata.h> + +static const char *opts_short = "b:i:a:p:v:V:gh"; static struct option options[] = { {"banks", required_argument, NULL, 'b'}, @@ -39,6 +46,8 @@ static struct option options[] = { {"guid", required_argument, NULL, 'g'}, {"active-bank", required_argument, NULL, 'a'}, {"previous-bank", required_argument, NULL, 'p'}, + {"version", required_argument, NULL, 'v'}, + {"vendor-file", required_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -49,9 +58,11 @@ static void print_usage(void) fprintf(stderr, "Options:\n" "\t-i, --images <num> Number of images (mandatory)\n" "\t-b, --banks <num> Number of banks (mandatory)\n" + "\t-v, --version Metadata version (mandatory)\n" "\t-a, --active-bank <num> Active bank (default=0)\n" "\t-p, --previous-bank <num> Previous active bank (default=active_bank - 1)\n" "\t-g, --guid Use GUID instead of UUID\n" + "\t-V, --vendor-file Vendor data file to append to the metadata\n" "\t-h, --help print a help message\n" ); fprintf(stderr, " UUIDs list syntax:\n" @@ -70,13 +81,28 @@ struct fwu_mdata_object { size_t images; size_t banks; size_t size; + u8 version; + size_t vsize; + void *vbuf; struct fwu_mdata *mdata; }; static int previous_bank, active_bank; static bool __use_guid; -static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks) +static bool supported_mdata_version(unsigned long version) +{ + switch (version) { + case 1: + case 2: + return true; + default: + return false; + } +} + +static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks, + u8 version, size_t vendor_size) { struct fwu_mdata_object *mobj; @@ -84,19 +110,40 @@ static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks) if (!mobj) return NULL; - mobj->size = sizeof(struct fwu_mdata) + - (sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * banks) * images; + if (version == 1) { + mobj->size = sizeof(struct fwu_mdata) + + (sizeof(struct fwu_image_entry) + + sizeof(struct fwu_image_bank_info) * banks) * images; + } else { + mobj->size = sizeof(struct fwu_mdata) + + sizeof(struct fwu_fw_store_desc) + + (sizeof(struct fwu_image_entry) + + sizeof(struct fwu_image_bank_info) * banks) * images; + + mobj->size += vendor_size; + mobj->vsize = vendor_size; + } + mobj->images = images; mobj->banks = banks; + mobj->version = version; mobj->mdata = calloc(1, mobj->size); - if (!mobj->mdata) { - free(mobj); - return NULL; + if (!mobj->mdata) + goto alloc_err; + + if (vendor_size) { + mobj->vbuf = calloc(1, mobj->vsize); + if (!mobj->vbuf) + goto alloc_err; } return mobj; + +alloc_err: + free(mobj->mdata); + free(mobj); + return NULL; } static struct fwu_image_entry * @@ -104,9 +151,18 @@ fwu_get_image(struct fwu_mdata_object *mobj, size_t idx) { size_t offset; - offset = sizeof(struct fwu_mdata) + - (sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * mobj->banks) * idx; + if (mobj->version == 1) { + offset = sizeof(struct fwu_mdata) + + (sizeof(struct fwu_image_entry) + + sizeof(struct fwu_image_bank_info) * mobj->banks) * + idx; + } else { + offset = sizeof(struct fwu_mdata) + + sizeof(struct fwu_fw_store_desc) + + (sizeof(struct fwu_image_entry) + + sizeof(struct fwu_image_bank_info) * mobj->banks) * + idx; + } return (struct fwu_image_entry *)((char *)mobj->mdata + offset); } @@ -116,11 +172,20 @@ fwu_get_bank(struct fwu_mdata_object *mobj, size_t img_idx, size_t bnk_idx) { size_t offset; - offset = sizeof(struct fwu_mdata) + - (sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * mobj->banks) * img_idx + - sizeof(struct fwu_image_entry) + - sizeof(struct fwu_image_bank_info) * bnk_idx; + if (mobj->version == 1) { + offset = sizeof(struct fwu_mdata) + + (sizeof(struct fwu_image_entry) + + sizeof(struct fwu_image_bank_info) * mobj->banks) * + img_idx + sizeof(struct fwu_image_entry) + + sizeof(struct fwu_image_bank_info) * bnk_idx; + } else { + offset = sizeof(struct fwu_mdata) + + sizeof(struct fwu_fw_store_desc) + + (sizeof(struct fwu_image_entry) + + sizeof(struct fwu_image_bank_info) * mobj->banks) * + img_idx + sizeof(struct fwu_image_entry) + + sizeof(struct fwu_image_bank_info) * bnk_idx; + } return (struct fwu_image_bank_info *)((char *)mobj->mdata + offset); } @@ -188,7 +253,7 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, return -EINVAL; if (strcmp(uuid, "0") && - uuid_guid_parse(uuid, (unsigned char *)&image->location_uuid) < 0) + uuid_guid_parse(uuid, (unsigned char *)&image->location_guid) < 0) return -EINVAL; /* Image type UUID */ @@ -196,7 +261,7 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, if (!uuid) return -EINVAL; - if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_uuid) < 0) + if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_guid) < 0) return -EINVAL; /* Fill bank image-UUID */ @@ -210,45 +275,118 @@ fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj, return -EINVAL; if (strcmp(uuid, "0") && - uuid_guid_parse(uuid, (unsigned char *)&bank->image_uuid) < 0) + uuid_guid_parse(uuid, (unsigned char *)&bank->image_guid) < 0) return -EINVAL; } return 0; } +#if defined(CONFIG_FWU_MDATA_V1) +static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj) +{ +} +#else +static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj) +{ + int i; + struct fwu_fw_store_desc *fw_desc; + struct fwu_mdata *mdata = mobj->mdata; + + mdata->metadata_size = mobj->size; + mdata->desc_offset = sizeof(struct fwu_mdata); + + for (i = 0; i < MAX_BANKS_V2; i++) + mdata->bank_state[i] = i < mobj->banks ? + BANK_ACCEPTED : BANK_INVALID; + + fw_desc = (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata)); + fw_desc->num_banks = mobj->banks; + fw_desc->num_images = mobj->images; + fw_desc->img_entry_size = sizeof(struct fwu_image_entry) + + (sizeof(struct fwu_image_bank_info) * mobj->banks); + fw_desc->bank_info_entry_size = + sizeof(struct fwu_image_bank_info); +} +#endif /* CONFIG_FWU_MDATA_V1 */ + /* Caller must ensure that @uuids[] has @mobj->images entries. */ static int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[]) { struct fwu_mdata *mdata = mobj->mdata; + char *vdata; int i, ret; - mdata->version = FWU_MDATA_VERSION; + mdata->version = mobj->version; mdata->active_index = active_bank; mdata->previous_active_index = previous_bank; + fwu_fill_version_specific_mdata(mobj); + for (i = 0; i < mobj->images; i++) { ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]); if (ret < 0) return ret; } + if (mobj->vsize) { + vdata = (char *)mobj->mdata + (mobj->size - mobj->vsize); + memcpy(vdata, mobj->vbuf, mobj->vsize); + } + mdata->crc32 = crc32(0, (const unsigned char *)&mdata->version, mobj->size - sizeof(uint32_t)); return 0; } -static int -fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output) +static int fwu_read_vendor_data(struct fwu_mdata_object *mobj, + const char *vendor_file) +{ + int ret = 0; + FILE *vfile = NULL; + + vfile = fopen(vendor_file, "r"); + if (!vfile) { + ret = -1; + goto out; + } + + if (fread(mobj->vbuf, 1, mobj->vsize, vfile) != mobj->vsize) + ret = -1; + +out: + fclose(vfile); + return ret; +} + +static int fwu_make_mdata(size_t images, size_t banks, u8 version, + const char *vendor_file, char *uuids[], + char *output) { - struct fwu_mdata_object *mobj; - FILE *file; int ret; + FILE *file; + struct stat sbuf; + size_t vendor_size = 0; + struct fwu_mdata_object *mobj; + + if (vendor_file) { + ret = stat(vendor_file, &sbuf); + if (ret) + return -errno; - mobj = fwu_alloc_mdata(images, banks); + vendor_size = sbuf.st_size; + } + + mobj = fwu_alloc_mdata(images, banks, version, vendor_size); if (!mobj) return -ENOMEM; + if (vendor_file) { + ret = fwu_read_vendor_data(mobj, vendor_file); + if (ret) + goto done_make; + } + ret = fwu_parse_fill_uuids(mobj, uuids); if (ret < 0) goto done_make; @@ -259,7 +397,7 @@ fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output) goto done_make; } - ret = fwrite(mobj->mdata, mobj->size, 1, file); + ret = fwrite(mobj->mdata, 1, mobj->size, file); if (ret != mobj->size) ret = -errno; else @@ -269,6 +407,7 @@ fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output) done_make: free(mobj->mdata); + free(mobj->vbuf); free(mobj); return ret; @@ -276,13 +415,15 @@ done_make: int main(int argc, char *argv[]) { - unsigned long banks = 0, images = 0; + unsigned long banks = 0, images = 0, version = 0; int c, ret; + const char *vendor_file; /* Explicitly initialize defaults */ active_bank = 0; __use_guid = false; previous_bank = INT_MAX; + vendor_file = NULL; do { c = getopt_long(argc, argv, opts_short, options, NULL); @@ -305,6 +446,12 @@ int main(int argc, char *argv[]) case 'a': active_bank = strtoul(optarg, NULL, 0); break; + case 'v': + version = strtoul(optarg, NULL, 0); + break; + case 'V': + vendor_file = optarg; + break; } } while (c != -1); @@ -313,6 +460,17 @@ int main(int argc, char *argv[]) return -EINVAL; } + if (!version || !supported_mdata_version(version)) { + fprintf(stderr, "Error: Version value can only be either 1 or 2, not %ld.\n", + version); + return -EINVAL; + } + + if (version == 1 && vendor_file) { + fprintf(stderr, "Error: Vendor Data can only be appended in version 2 of FWU Metadata.\n"); + return -EINVAL; + } + /* This command takes UUIDs * images and output file. */ if (optind + images + 1 != argc) { fprintf(stderr, "Error: UUID list or output file is not specified or too much.\n"); @@ -325,7 +483,8 @@ int main(int argc, char *argv[]) previous_bank = active_bank > 0 ? active_bank - 1 : banks - 1; } - ret = fwu_make_mdata(images, banks, argv + optind, argv[argc - 1]); + ret = fwu_make_mdata(images, banks, (u8)version, vendor_file, + argv + optind, argv[argc - 1]); if (ret < 0) fprintf(stderr, "Error: Failed to parse and write image: %s\n", strerror(-ret)); |