[PATCH 04/25] scripts: Add imx9image tool

Sascha Hauer s.hauer at pengutronix.de
Fri Nov 10 04:57:39 PST 2023


This adds a tool for building images for the NXP i.MX9 SoC. The code
is based on:
https://github.com/nxp-imx/imx-mkimage/tree/5a0faefc223e51e088433663b6e7d6fbce89bf59

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 include/soc/imx9/flash_header.h |   88 ++
 scripts/Kconfig                 |    7 +
 scripts/Makefile                |    1 +
 scripts/imx9image.c             | 2171 +++++++++++++++++++++++++++++++
 4 files changed, 2267 insertions(+)
 create mode 100644 include/soc/imx9/flash_header.h
 create mode 100644 scripts/imx9image.c

diff --git a/include/soc/imx9/flash_header.h b/include/soc/imx9/flash_header.h
new file mode 100644
index 0000000000..51819929dd
--- /dev/null
+++ b/include/soc/imx9/flash_header.h
@@ -0,0 +1,88 @@
+#ifndef SOC_IMX_FLASH_HEADER_H
+#define SOC_IMX_FLASH_HEADER_H
+
+#define HASH_MAX_LEN			64
+#define IV_MAX_LEN			32
+#define MAX_NUM_IMGS			8
+#define MAX_NUM_OF_CONTAINER		3
+#define MAX_HW_CFG_SIZE_V2		359
+
+struct img_flags {
+	char type;
+	char core_id;
+	char hash_type;
+	bool encrypted;
+	uint16_t boot_flags;
+};
+
+struct sig_blk_hdr {
+	uint8_t version;
+	uint16_t length;
+	uint8_t tag;
+	uint16_t srk_table_offset;
+	uint16_t cert_offset;
+	uint16_t blob_offset;
+	uint16_t signature_offset;
+	uint32_t reserved;
+} __attribute__((packed));
+
+struct boot_img {
+	uint32_t offset;
+	uint32_t size;
+	uint64_t dst;
+	uint64_t entry;
+	uint32_t hab_flags;
+	uint32_t meta;
+	uint8_t hash[HASH_MAX_LEN];
+	uint8_t iv[IV_MAX_LEN];
+} __attribute__((packed));
+
+struct flash_header_v3 {
+	uint8_t version;
+	uint16_t length;
+	uint8_t tag;
+	uint32_t flags;
+	uint16_t sw_version;
+	uint8_t fuse_version;
+	uint8_t num_images;
+	uint16_t sig_blk_offset;
+	uint16_t reserved;
+	struct boot_img img[MAX_NUM_IMGS];
+	struct sig_blk_hdr sig_blk_hdr;
+	uint32_t sigblk_size;
+	uint32_t padding;
+} __attribute__((packed));
+
+struct ivt_header {
+	uint8_t tag;
+	uint16_t length;
+	uint8_t version;
+} __attribute__((packed));
+
+struct write_dcd_command {
+	uint8_t tag;
+	uint16_t length;
+	uint8_t param;
+} __attribute__((packed));
+
+struct dcd_addr_data {
+	uint32_t addr;
+	uint32_t value;
+};
+
+struct dcd_v2_cmd {
+	struct write_dcd_command write_dcd_command; /*4*/
+	struct dcd_addr_data addr_data[MAX_HW_CFG_SIZE_V2]; /*2872*/
+} __attribute__((packed));
+
+struct dcd_v2 {
+	struct ivt_header header;   /*4*/
+	struct dcd_v2_cmd dcd_cmd; /*2876*/
+} __attribute__((packed)) ;                     /*2880*/
+
+struct imx_header_v3 {
+	struct flash_header_v3 fhdr[MAX_NUM_OF_CONTAINER];
+	struct dcd_v2 dcd_table;
+}  __attribute__((packed));
+
+#endif /* SOC_IMX_FLASH_HEADER_H */
diff --git a/scripts/Kconfig b/scripts/Kconfig
index 9be04fa7c8..4b675671ee 100644
--- a/scripts/Kconfig
+++ b/scripts/Kconfig
@@ -28,6 +28,13 @@ config ZYNQ_MKIMAGE
 	help
 	  This enables building the image creation tool for Zynq
 
+config IMX9_IMAGE
+	bool "imx9image"
+	depends on ARCH_IMX93 || COMPILE_HOST_TOOLS
+	default y if ARCH_IMX93
+	help
+	  This enables building the image tool for NXP i.MX9 SoCs
+
 config MXS_HOSTTOOLS
 	bool "MXS host tools" if COMPILE_HOST_TOOLS
 	depends on ARCH_MXS || COMPILE_HOST_TOOLS
diff --git a/scripts/Makefile b/scripts/Makefile
index 42ac4e548b..cb1d916439 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -25,6 +25,7 @@ hostprogs-always-$(CONFIG_SOCFPGA_MKIMAGE)		+= socfpga_mkimage
 hostprogs-always-$(CONFIG_MXS_HOSTTOOLS)		+= mxsimage mxsboot
 hostprogs-always-$(CONFIG_LAYERSCAPE_PBLIMAGE)		+= pblimage
 hostprogs-always-$(CONFIG_STM32_IMAGE)			+= stm32image
+hostprogs-always-$(CONFIG_IMX9_IMAGE)			+= imx9image
 hostprogs-always-$(CONFIG_RISCV)			+= prelink-riscv
 hostprogs-always-$(CONFIG_RK_IMAGE)			+= rkimage
 HOSTCFLAGS_rkimage.o = `$(PKG_CONFIG) --cflags openssl`
diff --git a/scripts/imx9image.c b/scripts/imx9image.c
new file mode 100644
index 0000000000..a991ba5f35
--- /dev/null
+++ b/scripts/imx9image.c
@@ -0,0 +1,2171 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ * derived from u-boot's mkimage utility
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <linux/kernel.h>
+
+#include "../include/soc/imx9/flash_header.h"
+#include "compiler.h"
+
+typedef enum option_type {
+	NO_IMG = 0,
+	DCD,
+	SCFW,
+	SECO,
+	M4,
+	AP,
+	OUTPUT,
+	SCD,
+	CSF,
+	FLAG,
+	DEVICE,
+	NEW_CONTAINER,
+	APPEND,
+	DATA,
+	PARTITION,
+	FILEOFF,
+	MSG_BLOCK,
+	DUMMY_V2X,
+	SENTINEL,
+	UPOWER,
+	FCB
+} option_type_t;
+
+typedef struct {
+	option_type_t option;
+	char* filename;
+	uint64_t src;
+	uint64_t dst;
+	uint64_t entry;/* image entry address or general purpose num */
+	uint64_t ext;
+	uint64_t mu;
+	uint64_t part;
+} image_t;
+
+typedef enum REVISION_TYPE {
+	NO_REV = 0,
+	A0,
+	B0
+} rev_type_t;
+
+typedef enum SOC_TYPE {
+	NONE = 0,
+	QX,
+	QM,
+	DXL,
+	ULP,
+	IMX9,
+} soc_type_t;
+
+#define CORE_SC         0x1
+#define CORE_CM4_0      0x2
+#define CORE_CM4_1      0x3
+#define CORE_CA53       0x4
+#define CORE_CA35       0x4
+#define CORE_CA72       0x5
+#define CORE_SECO       0x6
+#define CORE_V2X_P      0x9
+#define CORE_V2X_S      0xA
+
+#define CORE_ULP_CM33		0x1
+#define CORE_ULP_CA35		0x2
+#define CORE_ULP_UPOWER 	0x4
+#define CORE_ULP_SENTINEL 	0x6
+
+#define SC_R_OTP		357U
+#define SC_R_DEBUG		354U
+#define SC_R_ROM_0		236U
+#define SC_R_PWM_0		191U
+#define SC_R_SNVS		356U
+#define SC_R_DC_0		32U
+
+#define IMG_TYPE_CSF		0x01   /* CSF image type */
+#define IMG_TYPE_SCD		0x02   /* SCD image type */
+#define IMG_TYPE_EXEC		0x03   /* Executable image type */
+#define IMG_TYPE_DATA		0x04   /* Data image type */
+#define IMG_TYPE_DCD_DDR	0x05   /* DCD/DDR image type */
+#define IMG_TYPE_SECO		0x06   /* SECO image type */
+#define IMG_TYPE_SENTINEL	0x06   /* SENTINEL image type */
+#define IMG_TYPE_PROV		0x07   /* Provisioning image type */
+#define IMG_TYPE_DEK		0x08   /* DEK validation type */
+#define IMG_TYPE_FCB_CHK	0x08   /* The FCB copy image */
+#define IMG_TYPE_PRIM_V2X	0x0B   /* Primary V2X FW image */
+#define IMG_TYPE_SEC_V2X	0x0C   /* Secondary V2X FW image*/
+#define IMG_TYPE_V2X_ROM	0x0D   /* V2X ROM Patch image */
+#define IMG_TYPE_V2X_DUMMY	0x0E   /* V2X Dummy image */
+
+#define IMG_TYPE_SHIFT   0
+#define IMG_TYPE_MASK    0x1f
+#define IMG_TYPE(x)      (((x) & IMG_TYPE_MASK) >> IMG_TYPE_SHIFT)
+
+#define BOOT_IMG_FLAGS_CORE_MASK		0xF
+#define BOOT_IMG_FLAGS_CORE_SHIFT		0x04
+#define BOOT_IMG_FLAGS_CPU_RID_MASK		0x3FF0
+#define BOOT_IMG_FLAGS_CPU_RID_SHIFT		4
+#define BOOT_IMG_FLAGS_MU_RID_MASK		0xFFC000
+#define BOOT_IMG_FLAGS_MU_RID_SHIFT		14
+#define BOOT_IMG_FLAGS_PARTITION_ID_MASK	0x1F000000
+#define BOOT_IMG_FLAGS_PARTITION_ID_SHIFT	24
+
+#define SC_R_A35_0      508
+#define SC_R_A53_0      1
+#define SC_R_A72_0      6
+#define SC_R_MU_0A      213
+#define SC_R_MU_3A      216
+#define SC_R_M4_0_PID0  278
+#define SC_R_M4_0_MU_1A 297
+#define SC_R_M4_1_PID0  298
+#define SC_R_M4_1_MU_1A 317
+#define PARTITION_ID_M4 0
+#define PARTITION_ID_AP 1
+#define PARTITION_ID_AP2 3
+
+/* Command tags and parameters */
+#define HAB_DATA_WIDTH_BYTE 1 /* 8-bit value */
+#define HAB_DATA_WIDTH_HALF 2 /* 16-bit value */
+#define HAB_DATA_WIDTH_WORD 4 /* 32-bit value */
+#define HAB_CMD_WRT_DAT_MSK 1 /* mask/value flag */
+#define HAB_CMD_WRT_DAT_SET 2 /* set/clear flag */
+#define HAB_CMD_CHK_DAT_SET 2 /* set/clear flag */
+#define HAB_CMD_CHK_DAT_ANY 4 /* any/all flag */
+#define HAB_CMD_WRT_DAT_FLAGS_WIDTH   5 /* flags field width */
+#define HAB_CMD_WRT_DAT_FLAGS_SHIFT   3 /* flags field offset */
+#define HAB_CMD_WRT_DAT_BYTES_WIDTH   3 /* bytes field width */
+#define HAB_CMD_WRT_DAT_BYTES_SHIFT   0 /* bytes field offset */
+
+#define IVT_VER                         0x01
+#define IVT_VERSION                     0x43
+#define DCD_HEADER_TAG                  0xD2
+#define DCD_VERSION                     0x43
+#define DCD_WRITE_DATA_COMMAND_TAG      0xCC
+#define DCD_WRITE_DATA_PARAM            (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT) /* 0x4 */
+#define DCD_WRITE_CLR_BIT_PARAM         ((HAB_CMD_WRT_DAT_MSK << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0xC */
+#define DCD_WRITE_SET_BIT_PARAM         ((HAB_CMD_WRT_DAT_MSK << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_CMD_WRT_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x1C */
+#define DCD_CHECK_DATA_COMMAND_TAG      0xCF
+#define DCD_CHECK_BITS_CLR_PARAM        (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT) /* 0x04 */
+#define DCD_CHECK_BITS_SET_PARAM        ((HAB_CMD_CHK_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x14 */
+#define DCD_CHECK_ANY_BIT_CLR_PARAM     ((HAB_CMD_CHK_DAT_ANY << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x24 */
+#define DCD_CHECK_ANY_BIT_SET_PARAM     ((HAB_CMD_CHK_DAT_ANY << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_CMD_CHK_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x34 */
+
+#define IVT_OFFSET_NAND         (0x400)
+#define IVT_OFFSET_I2C          (0x400)
+#define IVT_OFFSET_FLEXSPI      (0x1000)
+#define IVT_OFFSET_SD           (0x400)
+#define IVT_OFFSET_SATA         (0x400)
+#define IVT_OFFSET_EMMC         (0x400)
+
+#define CSF_DATA_SIZE       (0x4000)
+#define INITIAL_LOAD_ADDR_SCU_ROM 0x2000e000
+#define INITIAL_LOAD_ADDR_AP_ROM 0x00110000
+#define INITIAL_LOAD_ADDR_FLEXSPI 0x08000000
+#define IMG_AUTO_ALIGN 0x10
+
+#define UNDEFINED 0xFFFFFFFF
+
+#define OCRAM_START						0x00100000
+#define OCRAM_END						0x00400000
+
+#define MAX_NUM_SRK_RECORDS		4
+
+#define IVT_HEADER_TAG_B0		0x87
+#define IVT_VERSION_B0			0x00
+
+#define IMG_FLAG_HASH_SHA256		0x000
+#define IMG_FLAG_HASH_SHA384		0x100
+#define IMG_FLAG_HASH_SHA512		0x200
+#define IMG_FLAG_HASH_SM3		0x300
+
+#define IMG_FLAG_ENCRYPTED_MASK		0x400
+#define IMG_FLAG_ENCRYPTED_SHIFT	0x0A
+
+#define IMG_FLAG_BOOTFLAGS_MASK		0xFFFF0000
+#define IMG_FLAG_BOOTFLAGS_SHIFT	0x10
+
+#define IMG_ARRAY_ENTRY_SIZE		128
+#define HEADER_IMG_ARRAY_OFFSET		0x10
+
+#define HASH_STR_SHA_256		"sha256"
+#define HASH_STR_SHA_384		"sha384"
+#define HASH_STR_SHA_512		"sha512"
+#define HASH_STR_SM3			"sm3"
+
+#define HASH_TYPE_SHA_256		256
+#define HASH_TYPE_SHA_384		384
+#define HASH_TYPE_SHA_512		512
+#define HASH_TYPE_SM3			003
+
+#define IMAGE_HASH_ALGO_DEFAULT		HASH_TYPE_SHA_384
+#define IMAGE_HASH_ALGO_DEFAULT_NAME	HASH_STR_SHA_384
+#define IMAGE_PADDING_DEFAULT		0x1000
+
+#define DCD_ENTRY_ADDR_IN_SCFW		0x240
+
+#define CONTAINER_ALIGNMENT		0x400
+#define CONTAINER_FLAGS_DEFAULT		0x10
+#define CONTAINER_FUSE_DEFAULT		0x0
+
+#define SIGNATURE_BLOCK_HEADER_LENGTH	0x10
+
+#define BOOT_IMG_META_MU_RID_SHIFT	10
+#define BOOT_IMG_META_PART_ID_SHIFT	20
+
+#define IMAGE_TYPE_MASK	0xF
+
+#define CORE_ID_SHIFT	0x4
+#define CORE_ID_MASK	0xF
+
+#define HASH_TYPE_SHIFT	0x8
+#define HASH_TYPE_MASK	0x7
+
+#define IMAGE_ENCRYPTED_SHIFT	0x11
+#define IMAGE_ENCRYPTED_MASK	0x1
+
+#define IMAGE_A35_DEFAULT_META(PART, SC_R_MU)						\
+	(((PART == 0 ) ? PARTITION_ID_AP : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT | SC_R_A35_0)
+
+#define IMAGE_A53_DEFAULT_META(PART, SC_R_MU)						\
+	(((PART == 0 ) ? PARTITION_ID_AP : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	 SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT |					\
+	 SC_R_A53_0)
+
+#define IMAGE_A72_DEFAULT_META(PART, SC_R_MU)						\
+	(((PART == 0 ) ? PARTITION_ID_AP2 : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	 SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT | SC_R_A72_0)
+
+#define IMAGE_M4_0_DEFAULT_META(PART)							\
+	(((PART == 0) ? PARTITION_ID_M4 : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	SC_R_M4_0_MU_1A << BOOT_IMG_META_MU_RID_SHIFT | SC_R_M4_0_PID0)
+
+#define IMAGE_M4_1_DEFAULT_META(PART)							\
+	(((PART == 0) ? PARTITION_ID_M4 : PART) << BOOT_IMG_META_PART_ID_SHIFT |	\
+	SC_R_M4_1_MU_1A << BOOT_IMG_META_MU_RID_SHIFT | SC_R_M4_1_PID0)
+
+#define CONTAINER_IMAGE_ARRAY_START_OFFSET	0x2000
+
+uint32_t scfw_flags = 0;
+
+static uint32_t custom_partition = 0;
+
+static void copy_file_aligned(int ifd, const char *datafile, int offset, int align)
+{
+	int dfd;
+	struct stat sbuf;
+	unsigned char *ptr;
+	uint8_t zeros[0x4000];
+	int size;
+	int ret;
+
+	if (align > 0x4000) {
+		fprintf (stderr, "Wrong alignment requested %d\n",
+			align);
+		exit (EXIT_FAILURE);
+	}
+
+	memset(zeros, 0, sizeof(zeros));
+
+	if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
+		fprintf (stderr, "Can't open %s: %s\n",
+			datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf (stderr, "Can't stat %s: %s\n",
+			datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (sbuf.st_size == 0)
+		goto close;
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf (stderr, "Can't read %s: %s\n",
+			datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	size = sbuf.st_size;
+	ret = lseek(ifd, offset, SEEK_SET);
+	if (ret < 0) {
+		fprintf(stderr, "%s: lseek error %s\n",
+			__func__, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (write(ifd, ptr, size) != size) {
+		fprintf (stderr, "Write error %s\n",
+			strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	align = ALIGN(size, align) - size;
+
+	if (write(ifd, (char *)&zeros, align) != align) {
+		fprintf(stderr, "Write error: %s\n",
+			strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+close:
+	(void) close (dfd);
+
+}
+
+static void set_imx_hdr_v3(struct imx_header_v3 *imxhdr, uint32_t dcd_len,
+		uint32_t flash_offset, uint32_t hdr_base, uint32_t cont_id)
+{
+	struct flash_header_v3 *fhdr_v3 = &imxhdr->fhdr[cont_id];
+
+	/* Set magic number */
+	fhdr_v3->tag = IVT_HEADER_TAG_B0;
+	fhdr_v3->version = IVT_VERSION_B0;
+}
+
+static void set_image_hash(struct boot_img *img, char *filename, uint32_t hash_type)
+{
+	FILE *fp = NULL;
+	char sha_command[512];
+	char digest_type[10];
+	char hash[2 * HASH_MAX_LEN + 1];
+	int digest_length = 0;
+	int i;
+
+	switch (hash_type) {
+	case HASH_TYPE_SHA_256:
+		img->hab_flags |= IMG_FLAG_HASH_SHA256;
+		strcpy(digest_type, "sha256sum" );
+		digest_length = 64;
+		break;
+	case HASH_TYPE_SHA_384:
+		img->hab_flags |= IMG_FLAG_HASH_SHA384;
+		strcpy(digest_type, "sha384sum" );
+		digest_length = 96;
+		break;
+	case HASH_TYPE_SHA_512:
+		img->hab_flags |= IMG_FLAG_HASH_SHA512;
+		strcpy(digest_type, "sha512sum" );
+		digest_length = 128;
+		break;
+	case HASH_TYPE_SM3:
+		img->hab_flags |= IMG_FLAG_HASH_SM3;
+		strcpy(digest_type, "sm3sum" );
+		digest_length = 64;
+		break;
+	default:
+		fprintf(stderr, "Wrong hash type selected (%d) !!!\n\n",
+				hash_type);
+		exit(EXIT_FAILURE);
+		break;
+	}
+
+	if (img->size == 0 || !filename)
+		sprintf(sha_command, "%s /dev/null", digest_type);
+	else
+		sprintf(sha_command, "dd status=none if=/dev/zero of=tmp_pad bs=%d count=1;\
+				dd status=none if=\'%s\' of=tmp_pad conv=notrunc;\
+				%s tmp_pad; rm -f tmp_pad",
+			img->size, filename, digest_type);
+
+	memset(img->hash, 0, HASH_MAX_LEN);
+
+	fp = popen(sha_command, "r");
+	if (fp == NULL) {
+		fprintf(stderr, "Failed to run command hash\n" );
+		exit(EXIT_FAILURE);
+	}
+
+	if (fgets(hash, digest_length + 1, fp) == NULL) {
+		fprintf(stderr, "Failed to hash file: %s\n", filename ? filename : "<none>");
+		exit(EXIT_FAILURE);
+	}
+
+	for (i = 0; i < strlen(hash)/2; i++)
+		sscanf(hash + 2*i, "%02hhx", &img->hash[i]);
+
+	pclose(fp);
+}
+
+#define append(p, s, l) do {memcpy(p, (uint8_t *)s, l); p += l; } while (0)
+
+static uint8_t *flatten_container_header(struct imx_header_v3 *imx_header,
+					uint8_t containers_count,
+					uint32_t *size_out, uint32_t file_offset)
+{
+	uint8_t *flat = NULL;
+	uint8_t *ptr = NULL;
+	uint16_t size = 0;
+	int i;
+
+	/* Compute size of all container headers */
+	for (i = 0; i < containers_count; i++) {
+
+		struct flash_header_v3 *container = &imx_header->fhdr[i];
+
+		container->sig_blk_offset = HEADER_IMG_ARRAY_OFFSET +
+			container->num_images * IMG_ARRAY_ENTRY_SIZE;
+
+		container->length = HEADER_IMG_ARRAY_OFFSET +
+			(IMG_ARRAY_ENTRY_SIZE * container->num_images) + sizeof(struct sig_blk_hdr);
+
+		/* Print info needed by CST to sign the container header */
+		printf("CST: CONTAINER %d offset: 0x%x\n", i, file_offset + size);
+		printf("CST: CONTAINER %d: Signature Block: offset is at 0x%x\n", i,
+						file_offset + size + container->length - SIGNATURE_BLOCK_HEADER_LENGTH);
+
+		printf("\tOffsets = \t0x%x \t0x%x\n", file_offset + size,
+						file_offset + size + container->length - SIGNATURE_BLOCK_HEADER_LENGTH);
+
+		size += ALIGN(container->length, container->padding);
+	}
+
+	flat = calloc(size, sizeof(uint8_t));
+	if (!flat) {
+		fprintf(stderr, "Failed to allocate memory (%d)\n", size);
+		exit(EXIT_FAILURE);
+	}
+
+	ptr = flat;
+	*size_out = size;
+
+	for (i = 0; i < containers_count; i++) {
+		struct flash_header_v3 *container = &imx_header->fhdr[i];
+		uint32_t container_start_offset = ptr - flat;
+		int j;
+
+		/* Append container header */
+		append(ptr, container, HEADER_IMG_ARRAY_OFFSET);
+
+		/* Adjust images offset to start from container headers start */
+		for (j = 0; j < container->num_images; j++)
+			container->img[j].offset -= container_start_offset + file_offset;
+
+		/* Append each image array entry */
+		for (j = 0; j < container->num_images; j++)
+			append(ptr, &container->img[j], sizeof(struct boot_img));
+
+		append(ptr, &container->sig_blk_hdr, sizeof(struct sig_blk_hdr));
+
+		/* Padding for container (if necessary) */
+		ptr += ALIGN(container->length, container->padding) - container->length;
+	}
+
+	return flat;
+}
+
+static uint64_t read_dcd_offset(char *filename)
+{
+	int dfd;
+	struct stat sbuf;
+	uint8_t *ptr;
+	uint64_t offset = 0;
+
+	dfd = open(filename, O_RDONLY|O_BINARY);
+	if (dfd < 0) {
+		fprintf(stderr, "Can't open %s: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf(stderr, "Can't stat %s: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "Can't read %s: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	offset = *(uint32_t *)(ptr + DCD_ENTRY_ADDR_IN_SCFW);
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+	(void) close(dfd);
+
+	return offset;
+}
+
+static uint32_t get_hash_algo(char *images_hash)
+{
+	uint32_t hash_algo;
+	const char *hash_name;
+
+	if (!images_hash) {
+		hash_algo = IMAGE_HASH_ALGO_DEFAULT;
+		hash_name = IMAGE_HASH_ALGO_DEFAULT_NAME;
+	} else if (!strcmp(images_hash, HASH_STR_SHA_256)) {
+		hash_algo = HASH_TYPE_SHA_256;
+		hash_name = HASH_STR_SHA_256;
+	} else if (!strcmp(images_hash, HASH_STR_SHA_384)) {
+		hash_algo = HASH_TYPE_SHA_384;
+		hash_name = HASH_STR_SHA_384;
+	} else if (!strcmp(images_hash, HASH_STR_SHA_512)) {
+		hash_algo = HASH_TYPE_SHA_512;
+		hash_name = HASH_STR_SHA_512;
+	} else if (!strcmp(images_hash, HASH_STR_SM3)) {
+		hash_algo = HASH_TYPE_SM3;
+		hash_name = HASH_STR_SM3;
+	} else {
+		fprintf(stderr,
+			"\nERROR: %s is an invalid hash argument\n"
+			"    Expected values: %s, %s, %s, %s\n\n",
+			images_hash, HASH_STR_SHA_256, HASH_STR_SHA_384,
+			HASH_STR_SHA_512, HASH_STR_SM3);
+		exit(EXIT_FAILURE);
+	}
+
+	printf("image hash type:\t%s\n", hash_name);
+	return hash_algo;
+}
+
+static void set_image_array_entry(struct flash_header_v3 *container, soc_type_t soc,
+		const image_t *image_stack, uint32_t offset,
+		uint32_t size, char *tmp_filename, bool dcd_skip, char *images_hash)
+{
+	uint64_t entry = image_stack->entry;
+	uint64_t dst = image_stack->dst;
+	uint64_t core = image_stack->ext;
+	uint32_t meta;
+	char *tmp_name = "";
+	option_type_t type = image_stack->option;
+	struct boot_img *img = &container->img[container->num_images];
+
+	if (container->num_images >= MAX_NUM_IMGS) {
+		fprintf(stderr, "Error: Container allows 8 images at most\n");
+		exit(EXIT_FAILURE);
+	}
+
+	img->offset = offset;  /* Is re-adjusted later */
+	img->size = size;
+
+	set_image_hash(img, tmp_filename, get_hash_algo(images_hash));
+
+	switch (type) {
+	case SECO:
+		if (container->num_images > 0) {
+			fprintf(stderr, "Error: SECO container only allows 1 image\n");
+			exit(EXIT_FAILURE);
+		}
+
+		img->hab_flags |= IMG_TYPE_SECO;
+		img->hab_flags |= CORE_SECO << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "SECO";
+		img->dst = 0x20C00000;
+		img->entry = 0x20000000;
+
+		break;
+	case SENTINEL:
+		if (container->num_images > 0) {
+			fprintf(stderr, "Error: SENTINEL container only allows 1 image\n");
+			exit(EXIT_FAILURE);
+		}
+
+		img->hab_flags |= IMG_TYPE_SENTINEL;
+		img->hab_flags |= CORE_ULP_SENTINEL << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "SENTINEL";
+		img->dst = 0XE7FE8000; /* S400 IRAM base */
+		img->entry = 0XE7FE8000;
+
+		break;
+	case AP:
+		if ((soc == QX || soc == DXL) && core == CORE_CA35)
+			meta = IMAGE_A35_DEFAULT_META(image_stack->part, image_stack->mu);
+		else if (soc == QM && core == CORE_CA53)
+			meta = IMAGE_A53_DEFAULT_META(image_stack->part, image_stack->mu);
+		else if (soc == QM && core == CORE_CA72)
+			meta = IMAGE_A72_DEFAULT_META(image_stack->part, image_stack->mu);
+		else if (((soc == ULP) || (soc == IMX9)) && core == CORE_CA35)
+			meta = 0;
+		else {
+			fprintf(stderr, "Error: invalid AP core id: %" PRIi64 "\n", core);
+			exit(EXIT_FAILURE);
+		}
+		img->hab_flags |= IMG_TYPE_EXEC;
+		if ((soc == ULP) || (soc == IMX9))
+			img->hab_flags |= CORE_ULP_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT;
+		else
+			img->hab_flags |= CORE_CA53 << BOOT_IMG_FLAGS_CORE_SHIFT; /* On B0, only core id = 4 is valid */
+		tmp_name = "AP";
+		img->dst = entry;
+		img->entry = entry;
+		img->meta = meta;
+		custom_partition = 0;
+		break;
+	case M4:
+		if ((soc == ULP) || (soc == IMX9)) {
+			core = CORE_ULP_CM33;
+			meta = 0;
+		} else if (core == 0) {
+			core = CORE_CM4_0;
+			meta = IMAGE_M4_0_DEFAULT_META(custom_partition);
+		} else if (core == 1) {
+			core = CORE_CM4_1;
+			meta = IMAGE_M4_1_DEFAULT_META(custom_partition);
+		} else {
+			fprintf(stderr, "Error: invalid m4 core id: %" PRIi64 "\n", core);
+			exit(EXIT_FAILURE);
+		}
+
+		img->hab_flags |= IMG_TYPE_EXEC;
+		img->hab_flags |= core << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "M4";
+		if ((entry & 0x7) != 0)
+			fprintf(stderr, "\n\nWarning: M4 Destination address is not 8 byte aligned\n\n");
+
+		if (dst)
+			img->dst = dst;
+		else
+			img->dst = entry;
+
+		img->entry = entry;
+		img->meta = meta;
+		custom_partition = 0;
+		break;
+	case DATA:
+		img->hab_flags |= IMG_TYPE_DATA;
+		if ((soc == ULP) || (soc == IMX9))
+			if (core == CORE_CM4_0)
+				img->hab_flags |= CORE_ULP_CM33 << BOOT_IMG_FLAGS_CORE_SHIFT;
+			else
+				img->hab_flags |= CORE_ULP_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT;
+		else
+			img->hab_flags |= core << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "DATA";
+		img->dst = entry;
+		break;
+	case MSG_BLOCK:
+		img->hab_flags |= IMG_TYPE_DATA;
+		img->hab_flags |= CORE_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT;
+		img->meta = core << BOOT_IMG_META_MU_RID_SHIFT;
+		tmp_name = "MSG_BLOCK";
+		img->dst = entry;
+		break;
+	case SCFW:
+		img->hab_flags |= scfw_flags & 0xFFFF0000;
+		img->hab_flags |= IMG_TYPE_EXEC;
+		img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "SCFW";
+		img->dst = 0x1FFE0000;
+		img->entry = 0x1FFE0000;
+
+		/* Lets add the DCD now */
+		if (!dcd_skip) {
+			container->num_images++;
+			img = &container->img[container->num_images];
+			img->hab_flags |= IMG_TYPE_DCD_DDR;
+			img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT;
+			set_image_hash(img, "/dev/null", IMAGE_HASH_ALGO_DEFAULT);
+			img->offset = offset + img->size;
+			img->entry = read_dcd_offset(tmp_filename);
+			img->dst = img->entry - 1;
+		}
+		break;
+	case UPOWER:
+		if (soc == ULP) {
+			img->hab_flags |= IMG_TYPE_EXEC;
+			img->hab_flags |= CORE_ULP_UPOWER << BOOT_IMG_FLAGS_CORE_SHIFT;
+			tmp_name = "UPOWER";
+			img->dst = 0x28300200; /* UPOWER code RAM */
+			img->entry = 0x28300200;
+		}
+		break;
+	case DUMMY_V2X:
+		img->hab_flags |= IMG_TYPE_V2X_DUMMY;
+		img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT;
+		tmp_name = "V2X Dummy";
+		img->dst = entry;
+		img->entry = entry;
+		img->size = 0; /* dummy image has no size */
+		break;
+	case FCB:
+		img->hab_flags |= IMG_TYPE_FCB_CHK;
+		img->dst = entry;
+		tmp_name = "FCB";
+		break;
+	default:
+		fprintf(stderr, "unrecognized image type (%d)\n", type);
+		exit(EXIT_FAILURE);
+	}
+
+	printf("%s file_offset = 0x%x size = 0x%x\n", tmp_name, offset, size);
+
+	container->num_images++;
+}
+
+static void set_container(struct flash_header_v3 *container,  uint16_t sw_version,
+			uint32_t alignment, uint32_t flags, uint16_t fuse_version)
+{
+	container->sig_blk_hdr.tag = 0x90;
+	container->sig_blk_hdr.length = sizeof(struct sig_blk_hdr);
+	container->sw_version = sw_version;
+	container->padding = alignment;
+	container->fuse_version = fuse_version;
+	container->flags = flags;
+	printf("flags:\t\t\t0x%x\n", container->flags);
+}
+
+static int get_container_image_start_pos(image_t *image_stack, uint32_t align, soc_type_t soc,
+					 uint32_t *scu_cont_hdr_off)
+{
+	image_t *img_sp = image_stack;
+	/* 8K total container header */
+	int file_off = CONTAINER_IMAGE_ARRAY_START_OFFSET,  ofd = -1;
+	struct flash_header_v3 header;
+
+	while (img_sp->option != NO_IMG) {
+		if (img_sp->option != APPEND) {
+			img_sp++;
+			continue;
+		}
+
+		ofd = open(img_sp->filename, O_RDONLY);
+		if (ofd < 0) {
+			printf("Failure open first container file %s\n", img_sp->filename);
+			break;
+		}
+
+		if (soc == DXL) {
+			/* Skip SECO container, jump to V2X container */
+			if (lseek(ofd, CONTAINER_ALIGNMENT, SEEK_SET) < 0) {
+				printf("Failure Skip SECO header \n");
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		if (read(ofd, &header, sizeof(header)) != sizeof(header)) {
+			printf("Failure Read header \n");
+			exit(EXIT_FAILURE);
+		}
+
+		close(ofd);
+
+		if (header.tag != IVT_HEADER_TAG_B0) {
+			printf("header tag mismatch %x\n", header.tag);
+		} else if (header.num_images == 0) {
+			printf("image num is 0 \n");
+		} else {
+			file_off = header.img[header.num_images - 1].offset + header.img[header.num_images - 1].size;
+			if (soc == DXL) {
+				file_off += CONTAINER_ALIGNMENT;
+				*scu_cont_hdr_off = CONTAINER_ALIGNMENT + ALIGN(header.length, CONTAINER_ALIGNMENT);
+			} else {
+				*scu_cont_hdr_off = ALIGN(header.length, CONTAINER_ALIGNMENT);
+			}
+			file_off = ALIGN(file_off, align);
+		}
+
+		img_sp++;
+	}
+
+	return file_off;
+}
+
+static void check_file(struct stat *sbuf, char *filename)
+{
+	int tmp_fd  = open(filename, O_RDONLY | O_BINARY);
+
+	if (tmp_fd < 0) {
+		fprintf(stderr, "%s: Can't open: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (fstat(tmp_fd, sbuf) < 0) {
+		fprintf(stderr, "%s: Can't stat: %s\n", filename, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	close(tmp_fd);
+}
+
+static void copy_file(int ifd, const char *datafile, int pad, int offset)
+{
+	int dfd;
+	struct stat sbuf;
+	unsigned char *ptr;
+	int tail;
+	uint8_t zeros[4096];
+	int size, ret;
+
+	memset(zeros, 0, sizeof(zeros));
+
+	if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
+		fprintf(stderr, "Can't open %s: %s\n", datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (fstat(dfd, &sbuf) < 0) {
+		fprintf(stderr, "Can't stat %s: %s\n", datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (sbuf.st_size == 0)
+		goto close;
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf(stderr, "Can't read %s: %s\n", datafile, strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	size = sbuf.st_size;
+	ret = lseek(ifd, offset, SEEK_SET);
+	if (ret < 0) {
+		fprintf(stderr, "%s: lseek error %s\n", __func__, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if (write(ifd, ptr, size) != size) {
+		fprintf(stderr, "Write error %s\n", strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	tail = size % 4;
+	pad = pad - size;
+	if ((pad == 1) && (tail != 0)) {
+
+		if (write(ifd, zeros, 4 - tail) != 4 - tail) {
+			fprintf(stderr, "Write error on %s\n", strerror(errno));
+			exit (EXIT_FAILURE);
+		}
+	} else if (pad > 1) {
+		while (pad > 0) {
+			int todo = sizeof(zeros);
+
+			if (todo > pad)
+				todo = pad;
+			if (write(ifd, (char *)&zeros, todo) != todo) {
+				fprintf(stderr, "Write error: %s\n",
+					strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			pad -= todo;
+		}
+	}
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+close:
+	(void) close (dfd);
+}
+
+static int build_container_qx_qm_b0(soc_type_t soc, uint32_t sector_size, uint32_t ivt_offset,
+				    char *out_file, bool emmc_fastboot, image_t *image_stack,
+				    bool dcd_skip, uint8_t fuse_version, uint16_t sw_version,
+				    char *images_hash)
+{
+	int file_off, ofd = -1;
+	unsigned int dcd_len = 0;
+	struct imx_header_v3 imx_header = {};
+	image_t *img_sp = image_stack;
+	struct stat sbuf;
+	uint32_t size = 0;
+	uint32_t file_padding = 0;
+	int ret;
+	const char *platform;
+
+	int container = -1;
+	int cont_img_count = 0; /* indexes to arrange the container */
+
+	if (image_stack == NULL) {
+		fprintf(stderr, "Empty image stack ");
+		exit(EXIT_FAILURE);
+	}
+
+	switch (soc) {
+	case QX: platform = "i.MX8QXP B0"; break;
+	case QM: platform = "i.MX8QM B0"; break;
+	case DXL: platform = "i.MX8DXL A0"; break;
+	case ULP: platform = "i.MX8ULP A0"; break;
+	case IMX9: platform = "i.MX9"; break;
+	default:
+		exit(EXIT_FAILURE);
+	}
+
+	printf("Platform:\t\t%s\n", platform);
+
+	set_imx_hdr_v3(&imx_header, dcd_len, ivt_offset, INITIAL_LOAD_ADDR_SCU_ROM, 0);
+	set_imx_hdr_v3(&imx_header, 0, ivt_offset, INITIAL_LOAD_ADDR_AP_ROM, 1);
+
+	printf("ivt_offset:\t\t0x%x\n", ivt_offset);
+
+	file_off = get_container_image_start_pos(image_stack, sector_size, soc, &file_padding);
+	printf("container image offset (aligned): 0x%x\n", file_off);
+
+	printf("csf_off:\t\t0x%x\n", ivt_offset + file_off);
+
+	/* step through image stack and generate the header */
+	img_sp = image_stack;
+
+	while (img_sp->option != NO_IMG) { /* stop once we reach null terminator */
+		switch (img_sp->option) {
+		case FCB:
+		case AP:
+		case M4:
+		case SCFW:
+		case DATA:
+		case UPOWER:
+		case MSG_BLOCK:
+		case SENTINEL:
+			if (container < 0) {
+				fprintf(stderr, "No container found\n");
+				exit(EXIT_FAILURE);
+			}
+			check_file(&sbuf, img_sp->filename);
+			set_image_array_entry(&imx_header.fhdr[container],
+						soc,
+						img_sp,
+						file_off,
+						ALIGN(sbuf.st_size, sector_size),
+						img_sp->filename,
+						dcd_skip,
+						images_hash);
+			img_sp->src = file_off;
+
+			file_off += ALIGN(sbuf.st_size, sector_size);
+			cont_img_count++;
+			break;
+
+		case DUMMY_V2X:
+			if (container < 0) {
+				fprintf(stderr, "No container found\n");
+				exit(EXIT_FAILURE);
+			}
+			set_image_array_entry(&imx_header.fhdr[container],
+						soc,
+						img_sp,
+						file_off,
+						0,
+						NULL,
+						dcd_skip,
+						images_hash);
+			img_sp->src = file_off;
+
+			cont_img_count++;
+			break;
+
+		case SECO:
+			if (container < 0) {
+				fprintf(stderr, "No container found\n");
+				exit(EXIT_FAILURE);
+			}
+			check_file(&sbuf, img_sp->filename);
+			set_image_array_entry(&imx_header.fhdr[container],
+						soc,
+						img_sp,
+						file_off,
+						sbuf.st_size,
+						img_sp->filename,
+						dcd_skip,
+						"sha384");
+			img_sp->src = file_off;
+
+			file_off += sbuf.st_size;
+			cont_img_count++;
+			break;
+
+		case NEW_CONTAINER:
+			container++;
+			set_container(&imx_header.fhdr[container], sw_version,
+					CONTAINER_ALIGNMENT,
+					CONTAINER_FLAGS_DEFAULT,
+					fuse_version);
+			cont_img_count = 0; /* reset img count when moving to new container */
+			scfw_flags = 0;
+			break;
+
+		case APPEND:
+			/* nothing to do here, the container is appended in the output */
+			break;
+		case FLAG:
+			/* override the flags for scfw in current container */
+			scfw_flags = img_sp->entry & 0xFFFF0000;/* mask off bottom 16 bits */
+			break;
+		case FILEOFF:
+			if (file_off > img_sp->dst) {
+				fprintf(stderr, "FILEOFF address less than current file offset!!!\n");
+				exit(EXIT_FAILURE);
+			}
+			if (img_sp->dst != ALIGN(img_sp->dst, sector_size)) {
+				fprintf(stderr, "FILEOFF address is not aligned to sector size!!!\n");
+				exit(EXIT_FAILURE);
+			}
+			file_off = img_sp->dst;
+			break;
+		case PARTITION: /* keep custom partition until next executable image */
+			custom_partition = img_sp->entry; /* use a global var for default behaviour */
+			break;
+		default:
+			fprintf(stderr, "unrecognized option in input stack (%d)\n", img_sp->option);
+			exit(EXIT_FAILURE);
+		}
+		img_sp++;/* advance index */
+	}
+
+	/* Open output file */
+	ofd = open(out_file, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
+	if (ofd < 0) {
+		fprintf(stderr, "%s: Can't open: %s\n",
+				out_file, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Append container (if specified) */
+	img_sp = image_stack;
+	while (img_sp->option != NO_IMG) {
+		if (img_sp->option == APPEND)
+			copy_file(ofd, img_sp->filename, 0, 0);
+
+		img_sp++;
+	}
+
+	/* Add padding or skip appended container */
+	ret = lseek(ofd, file_padding, SEEK_SET);
+	if (ret < 0) {
+		fprintf(stderr, "%s: lseek error %s\n", __func__, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Note: Image offset are not contained in the image */
+	uint8_t *tmp = flatten_container_header(&imx_header, container + 1, &size, file_padding);
+	/* Write image header */
+	if (write(ofd, tmp, size) != size) {
+		fprintf(stderr, "error writing image hdr\n");
+		exit(1);
+	}
+
+	/* Clean-up memory used by the headers */
+	free(tmp);
+
+	if (emmc_fastboot)
+		ivt_offset = 0; /*set ivt offset to 0 if emmc */
+
+	/* step through the image stack again this time copying images to final bin */
+	img_sp = image_stack;
+	while (img_sp->option != NO_IMG) { /* stop once we reach null terminator */
+		if (img_sp->option == M4 ||
+		    img_sp->option == AP ||
+		    img_sp->option == DATA ||
+		    img_sp->option == SCD ||
+		    img_sp->option == SCFW ||
+		    img_sp->option == SECO ||
+		    img_sp->option == MSG_BLOCK ||
+		    img_sp->option == UPOWER ||
+		    img_sp->option == SENTINEL ||
+		    img_sp->option == FCB) {
+			copy_file_aligned(ofd, img_sp->filename, img_sp->src, sector_size);
+		}
+		img_sp++;
+	}
+
+	/* Close output file */
+	close(ofd);
+	return 0;
+}
+
+static struct img_flags parse_image_flags(uint32_t flags, char *flag_list, soc_type_t soc)
+{
+	struct img_flags img_flags;
+
+	strcpy(flag_list, "(");
+
+	/* first extract the image type */
+	strcat(flag_list, "IMG TYPE: ");
+	img_flags.type = flags & IMAGE_TYPE_MASK;
+
+	switch (img_flags.type) {
+
+	case 0x3:
+		strcat(flag_list, "Executable");
+		break;
+	case 0x4:
+		strcat(flag_list, "Data");
+		break;
+	case 0x5:
+		strcat(flag_list, "DDR Init");
+		break;
+	case 0x6:
+		if ((soc == ULP) || (soc == IMX9))
+			strcat(flag_list, "SENTINEL");
+		else
+			strcat(flag_list, "SECO");
+		break;
+	case 0x7:
+		strcat(flag_list, "Provisioning");
+		break;
+	case 0x8:
+		if (soc == IMX9)
+		    strcat(flag_list, "FCB Check");
+		else
+		    strcat(flag_list, "DEK validation");
+		break;
+	case 0xB:
+		strcat(flag_list, "Primary V2X FW image");
+		break;
+	case 0xC:
+		strcat(flag_list, "Secondary V2X FW image");
+		break;
+	case 0xD:
+		strcat(flag_list, "V2X ROM Patch image");
+		break;
+	case 0xE:
+		strcat(flag_list, "V2X Dummy image");
+		break;
+	default:
+		strcat(flag_list, "Invalid img type");
+		break;
+	}
+	strcat(flag_list, " | ");
+
+	/* next get the core id */
+	strcat(flag_list, "CORE ID: ");
+	img_flags.core_id = (flags >> CORE_ID_SHIFT) & CORE_ID_MASK;
+
+	if ((soc == ULP) || (soc == IMX9)) {
+		switch (img_flags.core_id) {
+		case CORE_ULP_CM33:
+			strcat(flag_list, "CORE_CM33");
+			break;
+		case CORE_ULP_SENTINEL:
+			strcat(flag_list, "CORE_SENTINEL");
+			break;
+		case CORE_ULP_UPOWER:
+			strcat(flag_list, "CORE_UPOWER");
+			break;
+		case CORE_ULP_CA35:
+			if (soc == IMX9)
+				strcat(flag_list, "CORE_CA55");
+			else
+				strcat(flag_list, "CORE_CA35");
+			break;
+		default:
+			strcat(flag_list, "Invalid core id");
+			break;
+		}
+	} else {
+		switch (img_flags.core_id) {
+		case CORE_SC:
+			strcat(flag_list, "CORE_SC");
+			break;
+		case CORE_CM4_0:
+			strcat(flag_list, "CORE_CM4_0");
+			break;
+		case CORE_CM4_1:
+			strcat(flag_list, "CORE_CM4_1");
+			break;
+		case CORE_CA53:
+			strcat(flag_list, "CORE_CA53");
+			break;
+		case CORE_CA72:
+			strcat(flag_list, "CORE_CA72");
+			break;
+		case CORE_SECO:
+			strcat(flag_list, "CORE_SECO");
+			break;
+		case CORE_V2X_P:
+			strcat(flag_list, "CORE_V2X_P");
+			break;
+		case CORE_V2X_S:
+			strcat(flag_list, "CORE_V2X_S");
+			break;
+		default:
+			strcat(flag_list, "Invalid core id");
+			break;
+		}
+	}
+	strcat(flag_list, " | ");
+
+	/* next get the hash type */
+	strcat(flag_list, "HASH TYPE: ");
+	img_flags.hash_type = (flags >> HASH_TYPE_SHIFT) & HASH_TYPE_MASK;
+
+	switch (img_flags.hash_type) {
+	case 0x0:
+		strcat(flag_list, "SHA256");
+		break;
+	case 0x1:
+		strcat(flag_list, "SHA384");
+		break;
+	case 0x2:
+		strcat(flag_list, "SHA512");
+		break;
+	case 0x3:
+		strcat(flag_list, "SM3");
+		break;
+	default:
+		break;
+	}
+	strcat(flag_list, " | ");
+
+	/* lastly, read the encrypted bit */
+	strcat(flag_list, "ENCRYPTED: ");
+	img_flags.encrypted = (flags >> IMAGE_ENCRYPTED_SHIFT) & IMAGE_ENCRYPTED_MASK;
+
+	if (img_flags.encrypted)
+		strcat(flag_list, "YES");
+	else
+		strcat(flag_list, "NO");
+
+	/* terminate flag string */
+	strcat(flag_list, ")");
+
+	return img_flags;
+}
+
+static void print_image_array_fields(struct flash_header_v3 *container_hdrs, soc_type_t soc, bool app_cntr)
+{
+	struct boot_img img; /* image array entry */
+	struct img_flags img_flags; /* image hab flags */
+	int hash_length = 0;
+	char img_name[32]; /* scfw, bootloader, etc. */
+	char hash_name[8]; /* sha256, sha384, or sha512 */
+	char flag_string[128]; /* text representation of image hab flags */
+	int i;
+
+	for (i = 0; i < container_hdrs->num_images; i++) {
+		/* get the next image array entry */
+		img = container_hdrs->img[i];
+
+		/* get the image flags */
+		img_flags = parse_image_flags(img.hab_flags, flag_string, soc);
+
+		/* determine the type of image */
+		switch (img_flags.type) {
+		case 0x3:
+			if ((soc == ULP) || (soc == IMX9)) {
+				if (img_flags.core_id == CORE_ULP_UPOWER)
+					strcpy(img_name, "uPower FW");
+				else if ((img_flags.core_id == CORE_ULP_CA35))
+					if (app_cntr)
+						strcpy(img_name, "A core Image");
+					else
+						strcpy(img_name, "Bootloader");
+				else if ((img_flags.core_id == CORE_ULP_CM33))
+					strcpy(img_name, "M33");
+
+			} else {
+				if (img_flags.core_id == CORE_SC)
+					strcpy(img_name, "SCFW");
+				else if ((img_flags.core_id == CORE_CA53) || (img_flags.core_id == CORE_CA72))
+					if (app_cntr)
+						strcpy(img_name, "A core Image");
+					else
+						strcpy(img_name, "Bootloader");
+				else if (img_flags.core_id == CORE_CM4_0)
+					strcpy(img_name, "M4_0");
+				else if (img_flags.core_id == CORE_CM4_1)
+					strcpy(img_name, "M4_1");
+			}
+			break;
+		case 0x4:
+			strcpy(img_name, "Data");
+			break;
+		case 0x5:
+			strcpy(img_name, "DDR Init");
+			break;
+		case 0x6:
+			if ((soc == ULP) || (soc == IMX9))
+				strcpy(img_name, "SENTINEL FW");
+			else
+				strcpy(img_name, "SECO FW");
+			break;
+		case 0x7:
+			strcpy(img_name, "Provisioning");
+			break;
+		case 0x8:
+			if (soc == IMX9)
+				strcpy(img_name, "FCB Check");
+			else
+				strcpy(img_name, "DEK Validation");
+			break;
+		case 0xB:
+			strcpy(img_name, "Primary V2X FW image");
+			break;
+		case 0xC:
+			strcpy(img_name, "Secondary V2X FW image");
+			break;
+		case 0xD:
+			strcpy(img_name, "V2X ROM Patch image");
+			break;
+		case 0xE:
+			strcpy(img_name, "V2X Dummy image");
+			break;
+		default:
+			strcpy(img_name, "Unknown image");
+			break;
+		}
+
+		/* get the image hash type */
+		switch (img_flags.hash_type) {
+		case 0x0:
+			hash_length = 256 / 8;
+			strcpy(hash_name, "SHA256");
+			break;
+		case 0x1:
+			hash_length = 384 / 8;
+			strcpy(hash_name, "SHA384");
+			break;
+		case 0x2:
+			hash_length = 512 / 8;
+			strcpy(hash_name, "SHA512");
+			break;
+		case 0x3:
+			hash_length = 256 / 8;
+			strcpy(hash_name, "SM3");
+			break;
+		default:
+			strcpy(hash_name, "Unknown");
+			break;
+		}
+
+		/* print the image array fields */
+		printf("%sIMAGE %d (%s)%s\n", "\x1B[33m", i+1, img_name, "\x1B[37m");
+		printf("Offset: %#X\n", img.offset);
+		printf("Size: %#X (%d)\n", img.size, img.size);
+		printf("Load Addr: %#lX\n", img.dst);
+		printf("Entry Addr: %#lX\n", img.entry);
+		printf("Flags: %#X %s\n", img.hab_flags, flag_string);
+
+		/* only print metadata and hash if the image isn't DDR init */
+		if (img_flags.type != 0x5) {
+			int j;
+
+			printf("Metadata: %#X\n", img.meta);
+
+			/* print the image hash */
+			printf("Hash: ");
+			for (j = 0; j < hash_length; j++)
+				printf("%02x", img.hash[j]);
+
+			printf(" (%s)\n", hash_name);
+
+		}
+		printf("\n");
+	}
+}
+
+static void print_container_hdr_fields(struct flash_header_v3 *container_hdrs, int num_cntrs,
+				       soc_type_t soc, bool app_cntr)
+{
+	int i;
+
+	for (i = 0; i < num_cntrs; i++) {
+		printf("\n");
+		printf("*********************************\n");
+		printf("*				*\n");
+		if (app_cntr)
+			printf("*          APP CONTAINER %-2d     *\n", i + 1);
+		else
+			printf("*          ROM CONTAINER %-2d     *\n", i + 1);
+		printf("*				*\n");
+		printf("*********************************\n\n");
+		printf("%16s", "Length: ");
+		printf("%#X (%d)\n", container_hdrs->length, container_hdrs->length);
+		printf("%16s", "Tag: ");
+		printf("%#X\n", container_hdrs->tag);
+		printf("%16s", "Version: ");
+		printf("%#X\n", container_hdrs->version);
+		printf("%16s", "Flags: ");
+		printf("%#X\n", container_hdrs->flags);
+		printf("%16s", "Num images: ");
+		printf("%d\n", container_hdrs->num_images);
+		printf("%16s", "Fuse version: ");
+		printf("%#X\n", container_hdrs->fuse_version);
+		printf("%16s", "SW version: ");
+		printf("%#X\n", container_hdrs->sw_version);
+		printf("%16s", "Sig blk offset: ");
+		printf("%#X\n\n", container_hdrs->sig_blk_offset);
+
+		print_image_array_fields(container_hdrs, soc, app_cntr);
+
+		container_hdrs++;
+	}
+}
+
+static int get_container_size(struct flash_header_v3 *phdr)
+{
+	uint8_t i = 0;
+	uint32_t max_offset = 0, img_end;
+
+	max_offset = phdr->length;
+
+	for (i = 0; i < phdr->num_images; i++) {
+		img_end = phdr->img[i].offset + phdr->img[i].size;
+		if (img_end > max_offset)
+			max_offset = img_end;
+	}
+
+	if (phdr->sig_blk_offset != 0) {
+		uint16_t len = phdr->sig_blk_hdr.length;
+
+		if (phdr->sig_blk_offset + len > max_offset)
+			max_offset = phdr->sig_blk_offset + len;
+	}
+
+	return max_offset;
+}
+
+static int search_app_container(struct flash_header_v3 *container_hdrs, int num_cntrs, int ifd,
+				struct flash_header_v3 *app_container_hdr)
+{
+	int off[MAX_NUM_OF_CONTAINER];
+	int end = 0, last = 0;
+	int img_array_entries = 0;
+	ssize_t rd_err;
+	off_t err;
+	int i;
+
+	off[0] = 0;
+
+	for (i = 0; i < num_cntrs; i++) {
+		end = get_container_size(&container_hdrs[i]);
+		if (end + off[i] > last)
+			last = end + off[i];
+
+		if ((i + 1) < num_cntrs)
+			off[i + 1] = off[i] + ALIGN(container_hdrs[i].length, CONTAINER_ALIGNMENT);
+	}
+
+	/* Check app container tag at each 1KB beginning until 16KB */
+	last = ALIGN(last, 0x400);
+	for (i = 0; i < 16; i++) {
+		last = last + (i * 0x400);
+		err = lseek(ifd, last, SEEK_SET);
+		if (err < 0)
+			break;
+
+		rd_err = read(ifd, (void *)app_container_hdr, 16);
+		if (rd_err < 0) {
+			fprintf(stderr, "Error reading from input binary\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/* check that the current container has a valid tag */
+		if (app_container_hdr->tag != IVT_HEADER_TAG_B0)
+			continue;
+
+		if (app_container_hdr->num_images > MAX_NUM_IMGS) {
+			fprintf(stderr, "This container includes %d images, beyond max 8 images\n",
+				app_container_hdr->num_images);
+			exit(EXIT_FAILURE);
+		}
+
+		/* compute the size of the image array */
+		img_array_entries = app_container_hdr->num_images * sizeof(struct boot_img);
+
+		/* read in the full image array */
+		rd_err = read(ifd, (void *)&app_container_hdr->img, img_array_entries);
+		if (rd_err < 0) {
+			fprintf(stderr, "Error reading from input binary\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/* read in signature block header */
+		if (app_container_hdr->sig_blk_offset != 0) {
+			lseek(ifd, last + app_container_hdr->sig_blk_offset, SEEK_SET);
+			rd_err = read(ifd, (void *)&app_container_hdr->sig_blk_hdr, sizeof(struct sig_blk_hdr));
+			if (rd_err == -1) {
+				fprintf(stderr, "Error reading from input binary\n");
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		return last;
+	}
+
+	return 0;
+}
+
+static int extract_container_images(struct flash_header_v3 *container_hdr, char *ifname, int num_cntrs,
+				    int ifd, soc_type_t soc, int app_cntr_off)
+{
+	uint32_t img_offset = 0; /* image offset from container header */
+	uint32_t img_size = 0; /* image size */
+	uint32_t file_off = 0; /* current offset within container binary */
+	const uint32_t pad = 0;
+	int ofd = 0;
+	int ret = 0;
+	uint32_t seco_off = 0;
+	char dd_cmd[512]; /* dd cmd to extract each image from container binary */
+	struct stat buf;
+	FILE *f_ptr = NULL; /* file pointer to the dd process */
+	char *mem_ptr; /* pointer to input container in memory */
+	int i, j;
+
+	printf("Extracting container images...\n");
+
+	/* create output directory if it does not exist */
+	if (stat("extracted_imgs", &buf) == -1)
+		mkdir("extracted_imgs", S_IRWXU|S_IRWXG|S_IRWXO);
+
+	/* open container binary and map to memory */
+	fstat(ifd, &buf);
+	mem_ptr = mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
+
+	for (i = 0; i < num_cntrs; i++) {
+		for (j = 0; j < container_hdr->num_images; j++) {
+
+			/* first get the image offset and size from the container header */
+			img_offset = container_hdr->img[j].offset;
+			img_size = container_hdr->img[j].size;
+
+			if (!img_size) {
+				/* check for images with zero size (DDR Init) */
+				continue;
+			} else if (app_cntr_off > 0) {
+				sprintf(dd_cmd, "dd status=none if=%s of=extracted_imgs/app_container%d_img%d.bin ibs=1 skip=%d count=%d conv=notrunc",
+						ifname, i+1, j+1, app_cntr_off+img_offset, img_size);
+				printf("APP Container %d Image %d -> extracted_imgs/app_container%d_img%d.bin\n", i+1, j+1, i+1, j+1);
+
+			} else if ((i == 0) && (soc != DXL)) { /* first container is always SECO FW */
+				int k;
+
+				/* open output file */
+				ofd = open("extracted_imgs/ahab-container.img", O_CREAT|O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO);
+
+				/* first copy container header to output image */
+				ret = write(ofd, (void *)mem_ptr, 1024);
+				if (ret < 0)
+					fprintf(stderr, "Error writing to output file\n");
+
+
+				/* next, pad the output with zeros until the start of the image */
+				for (k = 0; k < (img_offset-CONTAINER_ALIGNMENT)/4; k++)
+					ret = write(ofd, (void *)&pad, 4);
+
+				/* now write the fw image to the output file */
+				ret = write(ofd, (void *)(mem_ptr+img_offset), img_size);
+				if (ret < 0)
+					fprintf(stderr, "Error writing to output file\n");
+
+				/* close output file and unmap input file */
+				close(ofd);
+
+				printf("Container %d Image %d -> extracted_imgs/ahab-container.img\n", i+1, j+1);
+
+			} else if ((i < 2 ) && (soc == DXL)) { /* Second Container is Always V2X for DXL */
+				if (i == 0) {
+					/* open output file */
+					ofd = open("extracted_imgs/ahab-container.img", O_CREAT|O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO);
+
+					/* first copy container header to output image */
+					ret = write(ofd, (void *)mem_ptr, 0x400);
+					if (ret < 0)
+						fprintf(stderr, "Error writing to output file1\n");
+
+					/* For DXL go to next container to copy header */
+					seco_off = img_offset;
+					continue;
+				} else if (i == 1 && j == 0) {
+					int k;
+
+					/* copy v2x container header and seco fw */
+					ret = write(ofd,(void *) mem_ptr + file_off, container_hdr->length);
+					if (ret < 0)
+						fprintf(stderr, "Error writing to output file2\n");
+
+
+					/* next, pad the output with zeros until the start of SECO image */
+					for (k = 0; k < (seco_off - (file_off + container_hdr->length)) / 4; k++)
+						ret = write(ofd, (void *)&pad, 4);
+
+					/* now write the SECO fw image to the output file */
+					ret = write(ofd, (void *)(mem_ptr+seco_off), file_off + img_offset - seco_off);
+					if (ret < 0)
+						fprintf(stderr, "Error writing to output file3: %x\n",ret);
+				}
+
+				/* now write the next image to the output file */
+				ret = write(ofd, (void *)(mem_ptr + file_off + img_offset), img_size);
+				if (ret < 0)
+					fprintf(stderr, "Error writing to output file4: %x\n",ret);
+
+				/* Iterate through V2X container for other images */
+				if (j < (container_hdr->num_images - 1))
+					continue;
+
+				/* close output file and unmap input file */
+				close(ofd);
+
+
+				printf("Container %d Image %d -> extracted_imgs/v2x-container.img\n", i+1, j+1);
+
+			} else {
+				sprintf(dd_cmd, "dd status=none if=%s of=extracted_imgs/container%d_img%d.bin ibs=1 skip=%d count=%d conv=notrunc",
+						ifname, i+1, j+1, file_off+img_offset, img_size);
+				printf("Container %d Image %d -> extracted_imgs/container%d_img%d.bin\n", i+1, j+1, i+1, j+1);
+			}
+
+			/* run dd command to extract current image from container */
+			fprintf(stderr, "FOOO: %s\n", dd_cmd);
+			f_ptr = popen(dd_cmd, "r");
+			if (f_ptr == NULL) {
+				fprintf(stderr, "Failed to extract image\n");
+				exit(EXIT_FAILURE);
+			}
+
+			/* close the pipe */
+			pclose(f_ptr);
+		}
+
+		file_off += ALIGN(container_hdr->length, CONTAINER_ALIGNMENT);
+		container_hdr++;
+	}
+
+	munmap((void *)mem_ptr, buf.st_size);
+	printf("Done\n\n");
+	return 0;
+}
+
+static int parse_container_hdrs_qx_qm_b0(char *ifname, bool extract, soc_type_t soc, off_t file_off)
+{
+	int ifd; /* container file descriptor */
+	int max_containers = (soc == DXL) ? 3 : 2;
+	int cntr_num = 0; /* number of containers in binary */
+	int img_array_entries = 0; /* number of images in container */
+	ssize_t rd_err;
+	struct flash_header_v3 container_headers[MAX_NUM_OF_CONTAINER];
+	struct flash_header_v3 app_container_header;
+	int app_cntr_off;
+
+	/* initialize region of memory where flash header will be stored */
+	memset((void *)container_headers, 0, sizeof(container_headers));
+
+	/* open container binary */
+	ifd = open(ifname, O_RDONLY|O_BINARY);
+
+	if (file_off) /* inital offset within container binary */
+		lseek(ifd, file_off, SEEK_SET);
+
+	while (cntr_num < max_containers) {
+
+		/* read in next container header up to the image array */
+		rd_err = read(ifd, (void *)&container_headers[cntr_num], 16);
+		if (rd_err == -1) {
+			fprintf(stderr, "Error reading from input binary\n");
+			exit(EXIT_FAILURE);
+		}
+
+		/* check that the current container has a valid tag */
+		if (container_headers[cntr_num].tag != IVT_HEADER_TAG_B0)
+			break;
+
+		if (container_headers[cntr_num].num_images > MAX_NUM_IMGS) {
+			fprintf(stderr, "This container includes %d images, beyond max 8 images\n",
+				container_headers[cntr_num].num_images);
+			exit(EXIT_FAILURE);
+		}
+
+		/* compute the size of the image array */
+		img_array_entries = container_headers[cntr_num].num_images * sizeof(struct boot_img);
+
+		/* read in the full image array */
+		rd_err = read(ifd, (void *)&container_headers[cntr_num].img, img_array_entries);
+		if (rd_err == -1) {
+			fprintf(stderr, "Error reading from input binary\n");
+			exit(EXIT_FAILURE);
+		}
+
+		if (container_headers[cntr_num].sig_blk_offset != 0) {
+			/* read in signature block header */
+			lseek(ifd, file_off + container_headers[cntr_num].sig_blk_offset, SEEK_SET);
+			rd_err = read(ifd, (void *)&container_headers[cntr_num].sig_blk_hdr, sizeof(struct sig_blk_hdr));
+			if (rd_err == -1) {
+				fprintf(stderr, "Error reading from input binary\n");
+				exit(EXIT_FAILURE);
+			}
+		}
+
+		/* seek to next container in binary */
+		file_off += ALIGN(container_headers[cntr_num].length, CONTAINER_ALIGNMENT);
+		lseek(ifd, file_off, SEEK_SET);
+
+		/* increment current container count */
+		cntr_num++;
+	}
+
+
+	print_container_hdr_fields(container_headers, cntr_num, soc, false);
+
+	if (extract)
+		extract_container_images(container_headers, ifname, cntr_num, ifd, soc, 0);
+
+	app_cntr_off = search_app_container(container_headers, cntr_num, ifd, &app_container_header);
+
+	if (app_cntr_off > 0) {
+		print_container_hdr_fields(&app_container_header, 1, soc, true);
+		if (extract)
+			extract_container_images(&app_container_header, ifname, 1, ifd, soc, app_cntr_off);
+	}
+
+	close(ifd);
+
+	return 0;
+
+}
+
+#define IMG_STACK_SIZE			32 /* max of 32 images for commandline images */
+
+/*
+ * Read commandline parameters and construct the header in order
+ *
+ * This will then construct the image according to the header and
+ *
+ * parameters passed in
+ *
+ */
+int main(int argc, char **argv)
+{
+	int c;
+	char *ofname = NULL;
+	char *ifname = NULL;
+	bool output = false;
+	bool dcd_skip = false;
+	bool emmc_fastboot = false;
+	bool extract = false;
+	bool parse = false;
+
+	int container = -1;
+	image_t param_stack[IMG_STACK_SIZE];/* stack of input images */
+	int p_idx = 0;/* param index counter */
+	off_t file_off = 0;
+
+	uint32_t ivt_offset = IVT_OFFSET_SD;
+	uint32_t sector_size = 0x400; /* default sector size */
+	soc_type_t soc = NONE; /* Initially No SOC defined */
+
+	uint8_t  fuse_version = 0;
+	uint16_t sw_version   = 0;
+	char     *images_hash = NULL;
+
+	static struct option long_options[] = {
+		{"scfw", required_argument, NULL, 'f'},
+		{"seco", required_argument, NULL, 'O'},
+		{"m4", required_argument, NULL, 'm'},
+		{"ap", required_argument, NULL, 'a'},
+		{"dcd", required_argument, NULL, 'd'},
+		{"out", required_argument, NULL, 'o'},
+		{"flags", required_argument, NULL, 'l'},
+		{"scd", required_argument, NULL, 'x'},
+		{"csf", required_argument, NULL, 'z'},
+		{"dev", required_argument, NULL, 'e'},
+		{"soc", required_argument, NULL, 's'},
+		{"dummy",required_argument, NULL, 'y'},
+		{"container", no_argument, NULL, 'c'},
+		{"partition", required_argument, NULL, 'p'},
+		{"append", no_argument, NULL, 'A'},
+		{"data", required_argument, NULL, 'D'},
+		{"fileoff", required_argument, NULL, 'P'},
+		{"msg_blk", required_argument, NULL, 'M'},
+		{"fuse_version", required_argument, NULL, 'u'},
+		{"sw_version", required_argument, NULL, 'v'},
+		{"images_hash", required_argument, NULL, 'h'},
+		{"extract", required_argument, NULL, 'X'},
+		{"parse", required_argument, NULL, 'R'},
+		{"sentinel", required_argument, NULL, 'i'},
+		{"upower", required_argument, NULL, 'w'},
+		{"fcb", required_argument, NULL, 'b'},
+		{"padding", required_argument, NULL, 'G'},
+		{NULL, 0, NULL, 0}
+	};
+
+	/* scan in parameters in order */
+	while (1) {
+		/* getopt_long stores the option index here. */
+		int option_index = 0;
+
+		c = getopt_long_only (argc, argv, ":f:m:a:d:o:l:x:z:e:p:cu:v:h:i:w:",
+			long_options, &option_index);
+
+		/* Detect the end of the options. */
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 0:
+			fprintf(stderr, "option %s", long_options[option_index].name);
+			if (optarg)
+				fprintf(stderr, " with arg %s", optarg);
+			fprintf(stderr, "\n");
+			break;
+		case 'A':
+			param_stack[p_idx].option = APPEND;
+			param_stack[p_idx++].filename = argv[optind++];
+			break;
+		case 'p':
+			printf("PARTITION:\t%s\n", optarg);
+			param_stack[p_idx].option = PARTITION;
+			param_stack[p_idx++].entry = (uint32_t) strtoll(optarg, NULL, 0);
+			break;
+		case 's':
+			if (!strncmp(optarg, "QX", 2)) {
+				soc = QX;
+			} else if (!strncmp(optarg, "QM", 2)) {
+				soc = QM;
+			} else if (!strncmp(optarg, "DXL", 3)) {
+				soc = DXL;
+			} else if (!strncmp(optarg, "ULP", 3)) {
+				soc = ULP;
+			} else if (!strncmp(optarg, "IMX9", 4)) {
+				soc = IMX9;
+			} else {
+				printf("unrecognized SOC: %s \n",optarg);
+				exit(EXIT_FAILURE);
+			}
+			printf("SOC: %s \n",optarg);
+			break;
+		case 'b':
+			printf("FCB:\t%s\n", optarg);
+			param_stack[p_idx].option = FCB;
+			param_stack[p_idx].filename = optarg;
+			if (optind < argc && *argv[optind] != '-') {
+				param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+				p_idx++;
+			} else {
+				fprintf(stderr, "\n-fcb option require Two arguments: filename, load address in hex\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'i':
+			printf("SENTINEL:\t%s\n", optarg);
+			param_stack[p_idx].option = SENTINEL;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'w':
+			printf("UPOWER:\t%s\n", optarg);
+			param_stack[p_idx].option = UPOWER;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'f':
+			printf("SCFW:\t%s\n", optarg);
+			param_stack[p_idx].option = SCFW;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'O':
+			printf("SECO:\t%s\n", optarg);
+			param_stack[p_idx].option = SECO;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'd':
+			printf("DCD:\t%s\n", optarg);
+			if (soc == DXL) {
+				if (!strncmp(optarg, "skip", 4)) {
+					dcd_skip = true;
+				} else {
+					fprintf(stderr, "\n-dcd option requires argument skip\n\n");
+					exit(EXIT_FAILURE);
+				}
+			} else if ((soc == ULP) || (soc == IMX9)) {
+				fprintf(stderr, "\n-dcd option is not used on ULP and IMX9\n\n");
+				exit(EXIT_FAILURE);
+			} else {
+				param_stack[p_idx].option = DCD;
+				param_stack[p_idx].filename = optarg;
+				p_idx++;
+			}
+			break;
+		case 'D':
+			if ((soc == DXL) || (soc == ULP) || (soc == IMX9)) {
+				printf("Data:\t%s", optarg);
+				param_stack[p_idx].option = DATA;
+				param_stack[p_idx].filename = optarg;
+				if ((optind < argc && *argv[optind] != '-') &&
+				    (optind+1 < argc && *argv[optind+1] != '-' )) {
+					if (!strncmp(argv[optind], "a53", 3))
+						param_stack[p_idx].ext = CORE_CA53;
+					else if (!strncmp(argv[optind], "a55", 3))
+						param_stack[p_idx].ext = CORE_CA35; /* fake id for a55 */
+					else if (!strncmp(argv[optind], "a35", 3))
+						param_stack[p_idx].ext = CORE_CA35;
+					else if (!strncmp(argv[optind], "a72", 3))
+						param_stack[p_idx].ext = CORE_CA72;
+					else if (!strncmp(argv[optind], "m4_1", 4))
+						param_stack[p_idx].ext = CORE_CM4_1;
+					else if (!strncmp(argv[optind], "m4", 2))
+						param_stack[p_idx].ext = CORE_CM4_0;
+					else {
+						fprintf(stderr, "ERROR: incorrect core ID for --data option: %s\n", argv[optind]);
+						exit(EXIT_FAILURE);
+					}
+					printf("\tcore: %s\n", argv[optind++]);
+					param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+				} else {
+					fprintf(stderr, "\n-data option require THREE arguments: filename, core: a55/a35/a53/a72/m4_0/m4_1, load address in hex\n\n");
+					exit(EXIT_FAILURE);
+				}
+				p_idx++;
+			} else {
+				fprintf(stderr, "\n-data option is only used with -rev B0, or DXL or ULP or IMX9 soc.\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'm':
+			printf("CM4:\t%s", optarg);
+			param_stack[p_idx].option = M4;
+			param_stack[p_idx].filename = optarg;
+			if ((optind < argc && *argv[optind] != '-') &&
+			    (optind + 1 < argc &&*argv[optind+1] != '-' )) {
+				param_stack[p_idx].ext = strtol(argv[optind++], NULL, 0);
+				param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+				param_stack[p_idx].dst = 0;
+				printf("\tcore: %" PRIi64, param_stack[p_idx].ext);
+				printf(" entry addr: 0x%08" PRIx64 , param_stack[p_idx].entry);
+				if (optind < argc && *argv[optind] != '-') {
+					param_stack[p_idx].dst = (uint32_t) strtoll(argv[optind++], NULL, 0);
+					printf(" load addr: 0x%08" PRIx64 , param_stack[p_idx].dst);
+				}
+				printf("\n");
+				p_idx++;
+			} else {
+				fprintf(stderr, "\n-m4 option require FOUR arguments: filename, core: 0/1, entry address in hex, load address in hex(optional)\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'a':
+			printf("AP:\t%s", optarg);
+			param_stack[p_idx].option = AP;
+			param_stack[p_idx].filename = optarg;
+			if ((optind < argc && *argv[optind] != '-') &&
+			    (optind + 1 < argc &&*argv[optind+1] != '-' )) {
+				if (!strncmp(argv[optind], "a53", 3))
+					param_stack[p_idx].ext = CORE_CA53;
+				else if (!strncmp(argv[optind], "a55", 3))
+					param_stack[p_idx].ext = CORE_CA35; /* fake id for a55 */
+				else if (!strncmp(argv[optind], "a35", 3))
+					param_stack[p_idx].ext = CORE_CA35;
+				else if (!strncmp(argv[optind], "a72", 3))
+					param_stack[p_idx].ext = CORE_CA72;
+				else {
+					fprintf(stderr, "ERROR: AP Core not found %s\n", argv[optind+2]);
+					exit(EXIT_FAILURE);
+				}
+				printf("\tcore: %s", argv[optind++]);
+
+				param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+				param_stack[p_idx].mu = SC_R_MU_0A;
+				param_stack[p_idx].part = 1;
+
+				if (optind < argc && *argv[optind] != '-') {
+					if (!strncmp(argv[optind], "mu0", 3))
+						param_stack[p_idx].mu = SC_R_MU_0A;
+					else if (!strncmp(argv[optind], "mu3", 3))
+						param_stack[p_idx].mu = SC_R_MU_3A;
+					else {
+						fprintf(stderr, "ERROR: MU number %s not found\n", argv[optind]);
+						exit(EXIT_FAILURE);
+					}
+					printf("\tMU: %s ", argv[optind++]);
+				}
+				if (optind < argc && *argv[optind] != '-') {
+					if (!strncmp(argv[optind], "pt", 2) &&
+					    (argv[optind][2] > '0') &&
+					    (argv[optind][2] != '2') &&
+					    (argv[optind][2] <= '9')) {
+						char str[2];
+						str[0] = argv[optind][2];
+						str[1] = '\0';
+						param_stack[p_idx].part = strtoll(str, NULL, 0);
+					} else {
+						fprintf(stderr, "ERROR: partition number %s not found\n", argv[optind]);
+						exit(EXIT_FAILURE);
+					}
+					printf("\tPartition: %s ", argv[optind++]);
+				}
+				printf(" addr: 0x%08" PRIx64 "\n", param_stack[p_idx++].entry);
+			} else {
+				fprintf(stderr, "\n-ap option require THREE arguments: filename, a35/a53/a72, start address in hex\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'l':
+			printf("FLAG:\t%s\n", optarg);
+			param_stack[p_idx].option = FLAG;
+			param_stack[p_idx++].entry = (uint32_t) strtoll(optarg, NULL, 0);
+			break;
+		case 'o':
+			printf("Output:\t%s\n", optarg);
+			ofname = optarg;
+			output = true;
+			break;
+		case 'x':
+			printf("SCD:\t%s\n", optarg);
+			param_stack[p_idx].option = SCD;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'z':
+			printf("CSF:\t%s\n", optarg);
+			param_stack[p_idx].option = CSF;
+			param_stack[p_idx++].filename = optarg;
+			break;
+		case 'e':
+			printf("BOOT DEVICE:\t%s\n", optarg);
+			if (!strcmp(optarg, "flexspi")) {
+				ivt_offset = IVT_OFFSET_FLEXSPI;
+			} else if (!strcmp(optarg, "sd")) {
+				ivt_offset = IVT_OFFSET_SD;
+			} else if (!strcmp(optarg, "nand")) {
+				sector_size = 0x8000;/* sector size for NAND */
+				if ((soc == DXL) || (soc == IMX9)) {
+					if (optind < argc && *argv[optind] != '-') {
+						if (!strcmp(argv[optind], "4K")) {
+							sector_size = 0x1000;
+						} else if (!strcmp(argv[optind], "8K")) {
+							sector_size = 0x2000;
+						} else if (!strcmp(argv[optind], "16K")) {
+							sector_size = 0x4000;
+						} else
+							printf("\nwrong nand page size:\r\n 4K\r\n8K\r\n16K\n\n");
+					} else {
+						printf("\n-dev nand requires the page size:\r\n 4K\r\n8K\r\n16K\n\n");
+					}
+				}
+			} else if (!strcmp(optarg, "emmc_fast")) {
+					ivt_offset = IVT_OFFSET_EMMC;
+					emmc_fastboot = true;/* emmc boot */
+			} else {
+				printf("\n-dev option, Valid boot devices are:\r\n sd\r\nflexspi\r\nnand\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'c':
+			printf("New Container: \t%d\n",++container);
+			param_stack[p_idx++].option = NEW_CONTAINER;
+			break;
+		case ':':
+			fprintf(stderr, "option %c missing arguments\n", optopt);
+			exit(EXIT_FAILURE);
+			break;
+		case 'P':
+			printf("FILEOFF:\t%s\n", optarg);
+			param_stack[p_idx].option = FILEOFF;
+			param_stack[p_idx++].dst = (uint64_t) strtoll(optarg, NULL, 0);
+			break;
+		case 'M':
+			printf("MSG BLOCK:\t%s", optarg);
+			param_stack[p_idx].option = MSG_BLOCK;
+			param_stack[p_idx].filename = optarg;
+			if ((optind < argc && *argv[optind] != '-') &&
+			    (optind+1 < argc &&*argv[optind + 1] != '-' )) {
+				if (!strncmp(argv[optind], "fuse", 4))
+					param_stack[p_idx].ext = SC_R_OTP;
+				else if (!strncmp(argv[optind], "debug", 5))
+					param_stack[p_idx].ext = SC_R_DEBUG;
+				else if (!strncmp(argv[optind], "field", 5))
+					param_stack[p_idx].ext = SC_R_ROM_0;
+				else if (!strncmp(argv[optind], "zero", 4))
+					param_stack[p_idx].ext = SC_R_PWM_0;
+				else if (!strncmp(argv[optind], "patch", 5))
+					param_stack[p_idx].ext = SC_R_SNVS;
+				else if (!strncmp(argv[optind], "degrade", 7))
+					param_stack[p_idx].ext = SC_R_DC_0;
+				else {
+					fprintf(stderr, "ERROR: MSG type not found %s\n", argv[optind+2]);
+					exit(EXIT_FAILURE);
+				}
+				printf("\ttype: %s", argv[optind++]);
+
+				param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0);
+
+				printf(" addr: 0x%08" PRIx64 "\n", param_stack[p_idx++].entry);
+			} else {
+				fprintf(stderr, "\nmsg block option require THREE arguments: filename, debug/fuse/field/patch, start address in hex\n\n");
+				exit(EXIT_FAILURE);
+			}
+			break;
+		case 'u':
+			fuse_version = (uint8_t) (strtoll(optarg, NULL, 0) & 0xFF);
+			break;
+		case 'v':
+			sw_version = (uint16_t) (strtoll(optarg, NULL, 0) & 0xFFFF);
+			break;
+		case 'h':
+			images_hash = optarg;
+			break;
+		case 'X':
+			printf("Input container binary to be deconstructed: %s\n", optarg);
+			ifname = optarg;
+			extract = true;
+			break;
+		case 'R':
+			printf("Input container binary to be parsed: %s\n", optarg);
+			ifname = optarg;
+			parse = true;
+			break;
+		case 'y':
+			printf("Dummy V2X image at:\t%s\n", optarg);
+			param_stack[p_idx].option = DUMMY_V2X;
+			param_stack[p_idx++].entry = (uint64_t) strtoll(optarg, NULL, 0);
+			break;
+		case 'G':
+			printf("Padding length:\t%s bytes\n", optarg);
+			file_off = atoi(optarg);
+			break;
+		case '?':
+		default:
+			/* invalid option */
+			fprintf(stderr, "option '%c' is invalid: ignored\n",
+				optopt);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (!parse) {
+		printf("CONTAINER FUSE VERSION:\t0x%02x\n", fuse_version);
+		printf("CONTAINER SW VERSION:\t0x%04x\n", sw_version);
+	}
+
+	param_stack[p_idx].option = NO_IMG; /* null terminate the img stack */
+
+	if (soc == NONE) {
+		fprintf(stderr, " No SOC defined");
+		exit(EXIT_FAILURE);
+	}
+
+	if (parse || extract) {
+		parse_container_hdrs_qx_qm_b0(ifname, extract, soc, file_off);
+		return 0;
+	}
+
+	if (container < 0) {
+		/* check to make sure there is at least 1 container defined */
+		fprintf(stderr, " No Container defined");
+		exit(EXIT_FAILURE);
+	}
+
+	if (!output) {
+		fprintf(stderr, "mandatory args scfw and output file name missing! abort\n");
+		exit(EXIT_FAILURE);
+	}
+
+	build_container_qx_qm_b0(soc, sector_size, ivt_offset, ofname, emmc_fastboot,
+				 (image_t *) param_stack, dcd_skip, fuse_version,
+				 sw_version, images_hash);
+
+	printf("DONE.\n");
+	printf("Note: Please copy image to offset: IVT_OFFSET + IMAGE_OFFSET\n");
+
+	return 0;
+}
+
-- 
2.39.2




More information about the barebox mailing list