aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-07-10 14:29:14 -0400
committerTom Rini <trini@konsulko.com>2023-07-10 14:29:14 -0400
commit146a82c017d51eb2c3b8be33854f200f1e52a1cb (patch)
treec2bb134d105bcc9855e6c39ac5b422e5416735ff /tools
parent05aa6516c6bb419d01d69fac457c0de563bfd694 (diff)
parent76c61f29d63163d178b1584ecc9fc2c96c538ff0 (diff)
downloadu-boot-WIP/10Jul2023.zip
u-boot-WIP/10Jul2023.tar.gz
u-boot-WIP/10Jul2023.tar.bz2
Merge branch 'next'WIP/10Jul2023
Diffstat (limited to 'tools')
-rw-r--r--tools/.gitignore1
-rw-r--r--tools/Kconfig9
-rw-r--r--tools/Makefile68
-rw-r--r--tools/eficapsule.h30
-rw-r--r--tools/env/.gitignore1
-rw-r--r--tools/mkeficapsule.c37
-rw-r--r--tools/mkfwumdata.c334
-rw-r--r--tools/relocate-rela.c2
8 files changed, 444 insertions, 38 deletions
diff --git a/tools/.gitignore b/tools/.gitignore
index cda3ea6..941d38d 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -34,6 +34,7 @@
/relocate-rela
/spl_size_limit
/sunxi-spl-image-builder
+/tools/generated/**/*.c
/update_octeon_header
/version.h
/xway-swap-bytes
diff --git a/tools/Kconfig b/tools/Kconfig
index 539708f..6e23f44 100644
--- a/tools/Kconfig
+++ b/tools/Kconfig
@@ -157,4 +157,13 @@ config LUT_SEQUENCE
help
Look Up Table Sequence
+config TOOLS_MKFWUMDATA
+ bool "Build mkfwumdata command"
+ default y if FWU_MULTI_BANK_UPDATE
+ help
+ This command allows users to create a raw image of the FWU
+ metadata for initial installation of the FWU multi bank
+ update on the board. The installation method depends on
+ the platform.
+
endmenu
diff --git a/tools/Makefile b/tools/Makefile
index d793cf3..3d0c4b0 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -48,20 +48,20 @@ hostprogs-$(CONFIG_VIDEO_LOGO) += bmp_logo
HOSTCFLAGS_bmp_logo.o := -pedantic
hostprogs-$(BUILD_ENVCRC) += envcrc
-envcrc-objs := envcrc.o lib/crc32.o env/embedded.o lib/sha1.o
+envcrc-objs := envcrc.o generated/lib/crc32.o generated/env/embedded.o generated/lib/sha1.o
hostprogs-$(CONFIG_CMD_NET) += gen_eth_addr
HOSTCFLAGS_gen_eth_addr.o := -pedantic
hostprogs-$(CONFIG_CMD_NET) += gen_ethaddr_crc
-gen_ethaddr_crc-objs := gen_ethaddr_crc.o lib/crc8.o
+gen_ethaddr_crc-objs := gen_ethaddr_crc.o generated/lib/crc8.o
HOSTCFLAGS_gen_ethaddr_crc.o := -pedantic
hostprogs-$(CONFIG_CMD_LOADS) += img2srec
HOSTCFLAGS_img2srec.o := -pedantic
hostprogs-y += mkenvimage
-mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o
+mkenvimage-objs := mkenvimage.o os_support.o generated/lib/crc32.o
hostprogs-y += dumpimage mkimage
hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fit_info fit_check_sign
@@ -71,30 +71,30 @@ ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST)$(CONFIG_FWU_MDATA_GPT_BLK),)
hostprogs-y += file2include
endif
-FIT_OBJS-y := fit_common.o fit_image.o image-host.o boot/image-fit.o
-FIT_SIG_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := image-sig-host.o boot/image-fit-sig.o
-FIT_CIPHER_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := boot/image-cipher.o
+FIT_OBJS-y := fit_common.o fit_image.o image-host.o generated/boot/image-fit.o
+FIT_SIG_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := image-sig-host.o generated/boot/image-fit-sig.o
+FIT_CIPHER_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := generated/boot/image-cipher.o
# The following files are synced with upstream DTC.
# Use synced versions from scripts/dtc/libfdt/.
LIBFDT_OBJS := $(addprefix libfdt/, fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o \
fdt_strerror.o fdt_empty_tree.o fdt_addresses.o fdt_overlay.o)
-RSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/rsa/, \
+RSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix generated/lib/rsa/, \
rsa-sign.o rsa-verify.o \
rsa-mod-exp.o)
-ECDSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/ecdsa/, ecdsa-libcrypto.o)
+ECDSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix generated/lib/ecdsa/, ecdsa-libcrypto.o)
-AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/aes/, \
+AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix generated/lib/aes/, \
aes-encrypt.o aes-decrypt.o)
# Cryptographic helpers and image types that depend on openssl/libcrypto
LIBCRYPTO_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := \
- lib/fdt-libcrypto.o \
+ generated/lib/fdt-libcrypto.o \
sunxi_toc0.o
-ROCKCHIP_OBS = lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
+ROCKCHIP_OBS = generated/lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
# common objs for dumpimage and mkimage
dumpimage-mkimage-objs := aisimage.o \
@@ -102,20 +102,20 @@ dumpimage-mkimage-objs := aisimage.o \
$(FIT_OBJS-y) \
$(FIT_SIG_OBJS-y) \
$(FIT_CIPHER_OBJS-y) \
- boot/fdt_region.o \
- boot/bootm.o \
- lib/crc32.o \
+ generated/boot/fdt_region.o \
+ generated/boot/bootm.o \
+ generated/lib/crc32.o \
default_image.o \
- lib/fdtdec_common.o \
- lib/fdtdec.o \
- boot/image.o \
- boot/image-host.o \
+ generated/lib/fdtdec_common.o \
+ generated/lib/fdtdec.o \
+ generated/boot/image.o \
+ generated/boot/image-host.o \
imagetool.o \
imximage.o \
imx8image.o \
imx8mimage.o \
kwbimage.o \
- lib/md5.o \
+ generated/lib/md5.o \
lpc32xximage.o \
mxsimage.o \
omapimage.o \
@@ -128,12 +128,12 @@ dumpimage-mkimage-objs := aisimage.o \
$(ROCKCHIP_OBS) \
socfpgaimage.o \
sunxi_egon.o \
- lib/crc16-ccitt.o \
- lib/hash-checksum.o \
- lib/sha1.o \
- lib/sha256.o \
- lib/sha512.o \
- common/hash.o \
+ generated/lib/crc16-ccitt.o \
+ generated/lib/hash-checksum.o \
+ generated/lib/sha1.o \
+ generated/lib/sha256.o \
+ generated/lib/sha512.o \
+ generated/common/hash.o \
ublimage.o \
zynqimage.o \
zynqmpimage.o \
@@ -213,7 +213,7 @@ HOSTCFLAGS_mxsboot.o := -pedantic
hostprogs-$(CONFIG_ARCH_SUNXI) += mksunxiboot
hostprogs-$(CONFIG_ARCH_SUNXI) += sunxi-spl-image-builder
-sunxi-spl-image-builder-objs := sunxi-spl-image-builder.o lib/bch.o
+sunxi-spl-image-builder-objs := sunxi-spl-image-builder.o generated/lib/bch.o
hostprogs-$(CONFIG_NETCONSOLE) += ncb
@@ -221,16 +221,16 @@ hostprogs-$(CONFIG_ARCH_KIRKWOOD) += kwboot
hostprogs-$(CONFIG_ARCH_MVEBU) += kwboot
hostprogs-y += proftool
-proftool-objs = proftool.o lib/abuf.o
+proftool-objs = proftool.o generated/lib/abuf.o
hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela
hostprogs-$(CONFIG_RISCV) += prelink-riscv
hostprogs-$(CONFIG_ARCH_OCTEON) += update_octeon_header
-update_octeon_header-objs := update_octeon_header.o lib/crc32.o
+update_octeon_header-objs := update_octeon_header.o generated/lib/crc32.o
hostprogs-y += fdtgrep
-fdtgrep-objs += $(LIBFDT_OBJS) boot/fdt_region.o fdtgrep.o
+fdtgrep-objs += $(LIBFDT_OBJS) generated/boot/fdt_region.o fdtgrep.o
ifneq ($(TOOLS_ONLY),y)
hostprogs-y += spl_size_limit
@@ -251,6 +251,10 @@ HOSTLDLIBS_mkeficapsule += \
$(shell pkg-config --libs uuid 2> /dev/null || echo "-luuid")
hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
+mkfwumdata-objs := mkfwumdata.o generated/lib/crc32.o
+HOSTLDLIBS_mkfwumdata += -luuid
+hostprogs-$(CONFIG_TOOLS_MKFWUMDATA) += mkfwumdata
+
# We build some files with extra pedantic flags to try to minimize things
# that won't build on some weird host compiler -- though there are lots of
# exceptions for files that aren't complaint.
@@ -262,12 +266,12 @@ HOSTCFLAGS_sha256.o := -pedantic
HOSTCFLAGS_sha512.o := -pedantic -DCONFIG_SHA512 -DCONFIG_SHA384
quiet_cmd_wrap = WRAP $@
-cmd_wrap = echo "\#include <../$(patsubst $(obj)/%,%,$@)>" >$@
+cmd_wrap = echo "\#include <../$(patsubst $(obj)/generated/%,%,$@)>" >$@
-$(obj)/boot/%.c $(obj)/common/%.c $(obj)/env/%.c $(obj)/lib/%.c:
+$(obj)/generated/%.c:
$(call cmd,wrap)
-clean-dirs := lib common
+clean-dirs := generated
always := $(hostprogs-y)
diff --git a/tools/eficapsule.h b/tools/eficapsule.h
index 072a4b5..753fb73 100644
--- a/tools/eficapsule.h
+++ b/tools/eficapsule.h
@@ -113,4 +113,34 @@ struct efi_firmware_image_authentication {
struct win_certificate_uefi_guid auth_info;
} __packed;
+/* fmp payload header */
+#define SIGNATURE_16(A, B) ((A) | ((B) << 8))
+#define SIGNATURE_32(A, B, C, D) \
+ (SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16))
+
+#define FMP_PAYLOAD_HDR_SIGNATURE SIGNATURE_32('M', 'S', 'S', '1')
+
+/**
+ * struct fmp_payload_header - EDK2 header for the FMP payload
+ *
+ * This structure describes the header which is preprended to the
+ * FMP payload by the edk2 capsule generation scripts.
+ *
+ * @signature: Header signature used to identify the header
+ * @header_size: Size of the structure
+ * @fw_version: Firmware versions used
+ * @lowest_supported_version: Lowest supported version (not used)
+ */
+struct fmp_payload_header {
+ uint32_t signature;
+ uint32_t header_size;
+ uint32_t fw_version;
+ uint32_t lowest_supported_version;
+};
+
+struct fmp_payload_header_params {
+ bool have_header;
+ uint32_t fw_version;
+};
+
#endif /* _EFI_CAPSULE_H */
diff --git a/tools/env/.gitignore b/tools/env/.gitignore
index 8d28b2b..804abac 100644
--- a/tools/env/.gitignore
+++ b/tools/env/.gitignore
@@ -1,3 +1,2 @@
-embedded.c
fw_printenv
fw_printenv_unstripped
diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
index b71537b..52be1f1 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -41,6 +41,7 @@ static struct option options[] = {
{"guid", required_argument, NULL, 'g'},
{"index", required_argument, NULL, 'i'},
{"instance", required_argument, NULL, 'I'},
+ {"fw-version", required_argument, NULL, 'v'},
{"private-key", required_argument, NULL, 'p'},
{"certificate", required_argument, NULL, 'c'},
{"monotonic-count", required_argument, NULL, 'm'},
@@ -60,6 +61,7 @@ static void print_usage(void)
"\t-g, --guid <guid string> guid for image blob type\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
+ "\t-v, --fw-version <version> firmware version\n"
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
@@ -402,6 +404,7 @@ 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,
+ struct fmp_payload_header_params *fmp_ph_params,
uint64_t mcount, char *privkey_file, char *cert_file,
uint16_t oemflags)
{
@@ -410,10 +413,11 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
struct efi_firmware_management_capsule_image_header image;
struct auth_context auth_context;
FILE *f;
- uint8_t *data;
+ uint8_t *data, *new_data, *buf;
off_t bin_size;
uint64_t offset;
int ret;
+ struct fmp_payload_header payload_header;
#ifdef DEBUG
fprintf(stderr, "For output: %s\n", path);
@@ -423,6 +427,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
auth_context.sig_size = 0;
f = NULL;
data = NULL;
+ new_data = NULL;
ret = -1;
/*
@@ -431,12 +436,30 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
if (read_bin_file(bin, &data, &bin_size))
goto err;
+ buf = data;
+
+ /* insert fmp payload header right before the payload */
+ if (fmp_ph_params->have_header) {
+ new_data = malloc(bin_size + sizeof(payload_header));
+ if (!new_data)
+ goto err;
+
+ payload_header.signature = FMP_PAYLOAD_HDR_SIGNATURE;
+ payload_header.header_size = sizeof(payload_header);
+ payload_header.fw_version = fmp_ph_params->fw_version;
+ payload_header.lowest_supported_version = 0; /* not used */
+ memcpy(new_data, &payload_header, sizeof(payload_header));
+ memcpy(new_data + sizeof(payload_header), data, bin_size);
+ buf = new_data;
+ bin_size += sizeof(payload_header);
+ }
+
/* first, calculate signature to determine its size */
if (privkey_file && cert_file) {
auth_context.key_file = privkey_file;
auth_context.cert_file = cert_file;
auth_context.auth.monotonic_count = mcount;
- auth_context.image_data = data;
+ auth_context.image_data = buf;
auth_context.image_size = bin_size;
if (create_auth_data(&auth_context)) {
@@ -536,7 +559,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
/*
* firmware binary
*/
- if (write_capsule_file(f, data, bin_size, "Firmware binary"))
+ if (write_capsule_file(f, buf, bin_size, "Firmware binary"))
goto err;
ret = 0;
@@ -545,6 +568,7 @@ err:
fclose(f);
free_sig_data(&auth_context);
free(data);
+ free(new_data);
return ret;
}
@@ -644,6 +668,7 @@ int main(int argc, char **argv)
unsigned long oemflags;
char *privkey_file, *cert_file;
int c, idx;
+ struct fmp_payload_header_params fmp_ph_params = { 0 };
guid = NULL;
index = 0;
@@ -679,6 +704,10 @@ int main(int argc, char **argv)
case 'I':
instance = strtoul(optarg, NULL, 0);
break;
+ case 'v':
+ fmp_ph_params.fw_version = strtoul(optarg, NULL, 0);
+ fmp_ph_params.have_header = true;
+ break;
case 'p':
if (privkey_file) {
fprintf(stderr,
@@ -751,7 +780,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
} else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
- index, instance, mcount, privkey_file,
+ index, instance, &fmp_ph_params, mcount, privkey_file,
cert_file, (uint16_t)oemflags) < 0) {
fprintf(stderr, "Creating firmware capsule failed\n");
exit(EXIT_FAILURE);
diff --git a/tools/mkfwumdata.c b/tools/mkfwumdata.c
new file mode 100644
index 0000000..9732a8d
--- /dev/null
+++ b/tools/mkfwumdata.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <u-boot/crc.h>
+#include <unistd.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>
+
+/* TODO: Endianness conversion may be required for some arch. */
+
+static const char *opts_short = "b:i:a:p:gh";
+
+static struct option options[] = {
+ {"banks", required_argument, NULL, 'b'},
+ {"images", required_argument, NULL, 'i'},
+ {"guid", required_argument, NULL, 'g'},
+ {"active-bank", required_argument, NULL, 'a'},
+ {"previous-bank", required_argument, NULL, 'p'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0},
+};
+
+static void print_usage(void)
+{
+ fprintf(stderr, "Usage: mkfwumdata [options] <UUIDs list> <output file>\n");
+ fprintf(stderr, "Options:\n"
+ "\t-i, --images <num> Number of images (mandatory)\n"
+ "\t-b, --banks <num> Number of banks (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-h, --help print a help message\n"
+ );
+ fprintf(stderr, " UUIDs list syntax:\n"
+ "\t <location uuid>,<image type uuid>,<images uuid list>\n"
+ "\t images uuid list syntax:\n"
+ "\t img_uuid_00,img_uuid_01...img_uuid_0b,\n"
+ "\t img_uuid_10,img_uuid_11...img_uuid_1b,\n"
+ "\t ...,\n"
+ "\t img_uuid_i0,img_uuid_i1...img_uuid_ib,\n"
+ "\t where 'b' and 'i' are number of banks and number\n"
+ "\t of images in a bank respectively.\n"
+ );
+}
+
+struct fwu_mdata_object {
+ size_t images;
+ size_t banks;
+ size_t size;
+ 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)
+{
+ struct fwu_mdata_object *mobj;
+
+ mobj = calloc(1, sizeof(*mobj));
+ if (!mobj)
+ return NULL;
+
+ mobj->size = sizeof(struct fwu_mdata) +
+ (sizeof(struct fwu_image_entry) +
+ sizeof(struct fwu_image_bank_info) * banks) * images;
+ mobj->images = images;
+ mobj->banks = banks;
+
+ mobj->mdata = calloc(1, mobj->size);
+ if (!mobj->mdata) {
+ free(mobj);
+ return NULL;
+ }
+
+ return mobj;
+}
+
+static struct fwu_image_entry *
+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;
+
+ return (struct fwu_image_entry *)((char *)mobj->mdata + offset);
+}
+
+static struct fwu_image_bank_info *
+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;
+
+ return (struct fwu_image_bank_info *)((char *)mobj->mdata + offset);
+}
+
+/**
+ * convert_uuid_to_guid() - convert UUID to GUID
+ * @buf: UUID binary
+ *
+ * UUID and GUID have the same data structure, but their binary
+ * formats are different due to the endianness. See lib/uuid.c.
+ * Since uuid_parse() can handle only UUID, this function must
+ * be called to get correct data for GUID when parsing a string.
+ *
+ * The correct data will be returned in @buf.
+ */
+static void convert_uuid_to_guid(unsigned char *buf)
+{
+ unsigned char c;
+
+ c = buf[0];
+ buf[0] = buf[3];
+ buf[3] = c;
+ c = buf[1];
+ buf[1] = buf[2];
+ buf[2] = c;
+
+ c = buf[4];
+ buf[4] = buf[5];
+ buf[5] = c;
+
+ c = buf[6];
+ buf[6] = buf[7];
+ buf[7] = c;
+}
+
+static int uuid_guid_parse(char *uuidstr, unsigned char *uuid)
+{
+ int ret;
+
+ ret = uuid_parse(uuidstr, uuid);
+ if (ret < 0)
+ return ret;
+
+ if (__use_guid)
+ convert_uuid_to_guid(uuid);
+
+ return ret;
+}
+
+static int
+fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj,
+ size_t idx, char *uuids)
+{
+ struct fwu_image_entry *image = fwu_get_image(mobj, idx);
+ struct fwu_image_bank_info *bank;
+ char *p = uuids, *uuid;
+ int i;
+
+ if (!image)
+ return -ENOENT;
+
+ /* Image location UUID */
+ uuid = strsep(&p, ",");
+ if (!uuid)
+ return -EINVAL;
+
+ if (strcmp(uuid, "0") &&
+ uuid_guid_parse(uuid, (unsigned char *)&image->location_uuid) < 0)
+ return -EINVAL;
+
+ /* Image type UUID */
+ uuid = strsep(&p, ",");
+ if (!uuid)
+ return -EINVAL;
+
+ if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_uuid) < 0)
+ return -EINVAL;
+
+ /* Fill bank image-UUID */
+ for (i = 0; i < mobj->banks; i++) {
+ bank = fwu_get_bank(mobj, idx, i);
+ if (!bank)
+ return -ENOENT;
+ bank->accepted = 1;
+ uuid = strsep(&p, ",");
+ if (!uuid)
+ return -EINVAL;
+
+ if (strcmp(uuid, "0") &&
+ uuid_guid_parse(uuid, (unsigned char *)&bank->image_uuid) < 0)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* 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;
+ int i, ret;
+
+ mdata->version = FWU_MDATA_VERSION;
+ mdata->active_index = active_bank;
+ mdata->previous_active_index = previous_bank;
+
+ for (i = 0; i < mobj->images; i++) {
+ ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ 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)
+{
+ struct fwu_mdata_object *mobj;
+ FILE *file;
+ int ret;
+
+ mobj = fwu_alloc_mdata(images, banks);
+ if (!mobj)
+ return -ENOMEM;
+
+ ret = fwu_parse_fill_uuids(mobj, uuids);
+ if (ret < 0)
+ goto done_make;
+
+ file = fopen(output, "w");
+ if (!file) {
+ ret = -errno;
+ goto done_make;
+ }
+
+ ret = fwrite(mobj->mdata, mobj->size, 1, file);
+ if (ret != mobj->size)
+ ret = -errno;
+ else
+ ret = 0;
+
+ fclose(file);
+
+done_make:
+ free(mobj->mdata);
+ free(mobj);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned long banks = 0, images = 0;
+ int c, ret;
+
+ /* Explicitly initialize defaults */
+ active_bank = 0;
+ __use_guid = false;
+ previous_bank = INT_MAX;
+
+ do {
+ c = getopt_long(argc, argv, opts_short, options, NULL);
+ switch (c) {
+ case 'h':
+ print_usage();
+ return 0;
+ case 'b':
+ banks = strtoul(optarg, NULL, 0);
+ break;
+ case 'i':
+ images = strtoul(optarg, NULL, 0);
+ break;
+ case 'g':
+ __use_guid = true;
+ break;
+ case 'p':
+ previous_bank = strtoul(optarg, NULL, 0);
+ break;
+ case 'a':
+ active_bank = strtoul(optarg, NULL, 0);
+ break;
+ }
+ } while (c != -1);
+
+ if (!banks || !images) {
+ fprintf(stderr, "Error: The number of banks and images must not be 0.\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");
+ print_usage();
+ return -ERANGE;
+ }
+
+ if (previous_bank == INT_MAX) {
+ /* set to the earlier bank in round-robin scheme */
+ previous_bank = active_bank > 0 ? active_bank - 1 : banks - 1;
+ }
+
+ ret = fwu_make_mdata(images, banks, argv + optind, argv[argc - 1]);
+ if (ret < 0)
+ fprintf(stderr, "Error: Failed to parse and write image: %s\n",
+ strerror(-ret));
+
+ return ret;
+}
diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c
index fe8cd6b..f230ec5 100644
--- a/tools/relocate-rela.c
+++ b/tools/relocate-rela.c
@@ -521,7 +521,7 @@ static int rela_elf32(char **argv, FILE *f)
uint32_t pos = rela_start + sizeof(Elf32_Rela) * i;
uint32_t addr, pos_dyn;
- debug("\nPossition:\t%d/0x%x\n", i, pos);
+ debug("\nPosition:\t%d/0x%x\n", i, pos);
if (fseek(f, pos, SEEK_SET) < 0) {
fprintf(stderr, "%s: %s: seek to %" PRIx32