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.ha...@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


Reply via email to