blob: 976a5a9c4ff60d08db76ee7bc8b58d131bd8e5b9 [file] [log] [blame]
/*
* Copyright 2017 NXP
*
* SPDX-License-Identifier: GPL-2.0+
* derived from u-boot's mkimage utility
*
*/
#include <inttypes.h>
#include "mkimage_common.h"
#define MAX_NUM_IMGS 6
#define IVT_HEADER_TAG 0xDE
typedef struct {
uint64_t src; /*8*/
uint64_t dst; /*8*/
uint64_t entry; /*8*/
uint32_t size; /*4*/
uint32_t hab_flags; /*4*/
uint32_t flags1; /*4*/
uint32_t flags2; /*4*/
} __attribute__((packed)) boot_img_t;; /*40*/
typedef struct {
uint32_t num_images; /*4*/
uint32_t bd_size; /*4*/
uint32_t bd_flags; /*4*/
uint32_t reserved; /*4*/
boot_img_t img[MAX_NUM_IMGS]; /*240*/
} __attribute__((packed)) boot_data_v3_t; /*256*/
typedef struct {
ivt_header_t header; /*4*/
uint32_t ver; /*4*/
uint64_t dcd_ptr; /*8*/
uint64_t boot_data_ptr; /*8*/
uint64_t self; /*8*/
uint64_t csf; /*8*/
uint64_t next; /*8*/
} __attribute__((packed)) flash_header_v3_t; /*48*/
#define MAX_NUM_OF_CONTAINER 2
typedef struct {
flash_header_v3_t fhdr[MAX_NUM_OF_CONTAINER]; /*96*/
boot_data_v3_t boot_data[MAX_NUM_OF_CONTAINER]; /*512*/
dcd_v2_t dcd_table; /*2880*/
} __attribute__((packed)) imx_header_v3_t; /*3488*/
static void set_imx_hdr_v3(imx_header_v3_t *imxhdr, uint32_t dcd_len,
uint32_t flash_offset, uint32_t hdr_base, uint32_t cont_id)
{
flash_header_v3_t *fhdr_v3 = &imxhdr->fhdr[cont_id];
/* Set magic number */
fhdr_v3->header.tag = IVT_HEADER_TAG; /* 0xDE */
fhdr_v3->header.length = cpu_to_be16(sizeof(flash_header_v3_t));
fhdr_v3->header.version = IVT_VERSION; /* 0x43 */
fhdr_v3->ver = IVT_VER; /* 0x01 */
fhdr_v3->self = hdr_base + flash_offset + cont_id * sizeof(flash_header_v3_t);
if (dcd_len > 0)
fhdr_v3->dcd_ptr = hdr_base + flash_offset +
offsetof(imx_header_v3_t, dcd_table);
else
fhdr_v3->dcd_ptr = 0;
fhdr_v3->boot_data_ptr = hdr_base + flash_offset
+ offsetof(imx_header_v3_t, boot_data) + cont_id * sizeof(boot_data_v3_t);
fhdr_v3->csf = 0;
if ((cont_id + 1) < MAX_NUM_OF_CONTAINER)
fhdr_v3->next = (uintptr_t)&imxhdr->fhdr[cont_id + 1] - (uintptr_t)imxhdr;
else
fhdr_v3->next = 0;
}
int build_container_qx(uint32_t sector_size, uint32_t ivt_offset, char* out_file, bool emmc_fastboot, image_t* image_stack)
{
int file_off, ofd = -1;
unsigned int dcd_len = 0;
static imx_header_v3_t imx_header;
image_t* img_sp = image_stack;
struct stat sbuf;
uint64_t tmp_to = 0; /* used for offset of memory to find images */
uint32_t custom_partition = 0; /* 0 denotes default partition */
int container = -1;
int cont_img_count = 0; /* indexes to arrange the container */
memset((char*)&imx_header, 0, sizeof(imx_header_v3_t));
if(image_stack == NULL) {
fprintf(stderr, "Empty image stack ");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Platform:\ti.MX8QXP\n");
if(emmc_fastboot){/* start images after initial 8K */
file_off = 0x2000 - ivt_offset;
}
else
{
file_off = ALIGN(sizeof(imx_header_v3_t) + ivt_offset, sector_size);
}
do{ /* process DCD if it is found */
if (img_sp->option == DCD) {
dcd_len = parse_cfg_file(&imx_header.dcd_table, img_sp->filename);
fprintf(stdout, "dcd len = %d\n", dcd_len);
}
img_sp++;
}
while(img_sp->option!= NO_IMG);
/* change load addr and setup DCD to be attached to first container */
if (ivt_offset == IVT_OFFSET_FLEXSPI) {
set_imx_hdr_v3(&imx_header, dcd_len, ivt_offset, INITIAL_LOAD_ADDR_FLEXSPI, 0);
set_imx_hdr_v3(&imx_header, 0, ivt_offset, INITIAL_LOAD_ADDR_FLEXSPI, 1);
} else {
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);
}
/* 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 SCFW:
check_file(&sbuf, img_sp->filename);
fprintf(stdout, "scfw size = %" PRIi64 "\n", sbuf.st_size);
imx_header.boot_data[container].img[cont_img_count].src = file_off;
img_sp->src = file_off;
imx_header.boot_data[container].img[cont_img_count].dst = 0x1ffe0000; /* hard code scfw entry address */
imx_header.boot_data[container].img[cont_img_count].entry = 0x1ffe0000;
imx_header.boot_data[container].img[cont_img_count].size = sbuf.st_size;
imx_header.boot_data[container].img[cont_img_count].flags2 = 0;
imx_header.boot_data[container].img[cont_img_count].hab_flags = IMG_TYPE_EXEC;
imx_header.boot_data[container].img[cont_img_count].flags1 = (CORE_SC & BOOT_IMG_FLAGS_CORE_MASK);
imx_header.boot_data[container].num_images++;
imx_header.boot_data[container].bd_size = sizeof(boot_data_v3_t);
file_off += ALIGN(sbuf.st_size, sector_size);
tmp_to = ALIGN((imx_header.boot_data[container].img[cont_img_count].dst + sbuf.st_size), IMG_AUTO_ALIGN);
cont_img_count++;
break;
case M4:
check_file(&sbuf, img_sp->filename);
imx_header.boot_data[container].img[cont_img_count].src = file_off;
img_sp->src = file_off;
imx_header.boot_data[container].img[cont_img_count].dst = img_sp->entry;
imx_header.boot_data[container].img[cont_img_count].entry = img_sp->entry;
imx_header.boot_data[container].img[cont_img_count].size = sbuf.st_size;
imx_header.boot_data[container].num_images++;
imx_header.boot_data[container].img[cont_img_count].flags2 = 0;
imx_header.boot_data[container].img[cont_img_count].hab_flags = IMG_TYPE_EXEC;
if (img_sp->ext == 0) {
imx_header.boot_data[container].img[cont_img_count].flags1 = (CORE_CM4_0 & BOOT_IMG_FLAGS_CORE_MASK);
imx_header.boot_data[container].img[cont_img_count].flags1 |= (SC_R_M4_0_PID0 << BOOT_IMG_FLAGS_CPU_RID_SHIFT);
imx_header.boot_data[container].img[cont_img_count].flags1 |= (SC_R_M4_0_MU_1A << BOOT_IMG_FLAGS_MU_RID_SHIFT);
}
else if (img_sp->ext == 1) {
imx_header.boot_data[container].img[cont_img_count].flags1 = (CORE_CM4_1 & BOOT_IMG_FLAGS_CORE_MASK);
imx_header.boot_data[container].img[cont_img_count].flags1 |= (SC_R_M4_1_PID0 << BOOT_IMG_FLAGS_CPU_RID_SHIFT);
imx_header.boot_data[container].img[cont_img_count].flags1 |= (SC_R_M4_1_MU_1A << BOOT_IMG_FLAGS_MU_RID_SHIFT);
}
else{
fprintf(stderr, "Error: invalid m4 core id: %" PRIi64 "\n", img_sp->ext);
exit(EXIT_FAILURE);
}
if(custom_partition != 0)
{
imx_header.boot_data[container].img[cont_img_count].flags1 |= (custom_partition << BOOT_IMG_FLAGS_PARTITION_ID_SHIFT);
custom_partition = 0;
}
else
{
imx_header.boot_data[container].img[cont_img_count].flags1 |= (PARTITION_ID_M4 << BOOT_IMG_FLAGS_PARTITION_ID_SHIFT);
}
file_off += ALIGN(sbuf.st_size, sector_size);
cont_img_count++;
break;
case AP:
check_file(&sbuf, img_sp->filename);
imx_header.boot_data[container].img[cont_img_count].src = file_off;
img_sp->src = file_off;
imx_header.boot_data[container].img[cont_img_count].dst = img_sp->entry;
imx_header.boot_data[container].img[cont_img_count].size = sbuf.st_size;
imx_header.boot_data[container].img[cont_img_count].entry = img_sp->entry;
imx_header.boot_data[container].num_images++;
imx_header.boot_data[container].bd_size = sizeof(boot_data_v3_t);
imx_header.boot_data[container].bd_flags = 0;
imx_header.boot_data[container].img[cont_img_count].flags2 = 0;
imx_header.boot_data[container].img[cont_img_count].hab_flags = IMG_TYPE_EXEC;
imx_header.boot_data[container].img[cont_img_count].flags1 = (img_sp->ext & BOOT_IMG_FLAGS_CORE_MASK);
if (img_sp->ext != CORE_CA35) {
fprintf(stderr, "Error: invalid AP core id: %" PRIi64 "\n", img_sp->ext);
exit(EXIT_FAILURE);
}
imx_header.boot_data[container].img[cont_img_count].flags1 |= (SC_R_A35_0 << BOOT_IMG_FLAGS_CPU_RID_SHIFT);
imx_header.boot_data[container].img[cont_img_count].flags1 |= (SC_R_MU_0A << BOOT_IMG_FLAGS_MU_RID_SHIFT);
if(custom_partition != 0)
{
imx_header.boot_data[container].img[cont_img_count].flags1 |= (custom_partition << BOOT_IMG_FLAGS_PARTITION_ID_SHIFT);
custom_partition = 0;
}
else
{
imx_header.boot_data[container].img[cont_img_count].flags1 |= (PARTITION_ID_AP << BOOT_IMG_FLAGS_PARTITION_ID_SHIFT);
}
file_off += ALIGN(sbuf.st_size, sector_size);
cont_img_count++;
break;
case SCD:
check_file(&sbuf, img_sp->filename);
imx_header.boot_data[container].img[cont_img_count].src = file_off;
img_sp->src = file_off;
imx_header.boot_data[container].img[cont_img_count].dst = tmp_to;
imx_header.boot_data[container].img[cont_img_count].size = sbuf.st_size;
imx_header.boot_data[container].img[cont_img_count].flags2 = 0;
imx_header.boot_data[container].img[cont_img_count].hab_flags = IMG_TYPE_SCD;
imx_header.boot_data[container].img[cont_img_count].flags1 = (CORE_SC & BOOT_IMG_FLAGS_CORE_MASK);
imx_header.boot_data[container].num_images++; /* scd img is count in num_images */
tmp_to = ALIGN((tmp_to + sbuf.st_size), IMG_AUTO_ALIGN);
file_off += ALIGN(sbuf.st_size, sector_size);
cont_img_count++;
break;
case CSF:
check_file(&sbuf, img_sp->filename);
if (sbuf.st_size > CSF_DATA_SIZE) {
fprintf(stderr, "%s: file size %" PRIi64 " is larger than CSF_DATA_SIZE %d\n",
img_sp->filename, sbuf.st_size, CSF_DATA_SIZE);
exit(EXIT_FAILURE);
}
imx_header.boot_data[container].img[cont_img_count].src = file_off;
img_sp->src = file_off;
imx_header.boot_data[container].img[cont_img_count].dst = tmp_to;
imx_header.boot_data[container].img[cont_img_count].size = CSF_DATA_SIZE;
imx_header.boot_data[container].img[cont_img_count].flags2 = 0;
imx_header.boot_data[container].img[cont_img_count].hab_flags = IMG_TYPE_CSF;
imx_header.boot_data[container].img[cont_img_count].flags1 = (CORE_SC & BOOT_IMG_FLAGS_CORE_MASK);
imx_header.fhdr[container].csf = imx_header.boot_data[container].img[cont_img_count].dst;
imx_header.boot_data[container].num_images++; /* csf img is count in num_images */
tmp_to = ALIGN((tmp_to + CSF_DATA_SIZE), IMG_AUTO_ALIGN);
file_off += ALIGN(CSF_DATA_SIZE, sector_size);
cont_img_count++;
break;
case FLAG:
imx_header.boot_data[container].bd_flags = img_sp->entry;
break;
case NEW_CONTAINER: /* move the counters forward to start on a new container */
container++;
cont_img_count=0; /* reset img count when moving to new container */
break;
case PARTITION: /* keep custom partition until next executable image */
custom_partition = img_sp->entry;
break;
case DCD:
break; /* skip DCD here because we already processed it */
default:
fprintf(stderr, "unrecognized option in input stack");
exit(EXIT_FAILURE);
}
img_sp++;/* advance index */
}
/* reset counters to write output file */
container = 0;
cont_img_count = 0;
/* 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);
}
/* Note: Image offset are not contained in the image */
/* Write image header */
if (write(ofd, &imx_header, sizeof(imx_header_v3_t)) != sizeof(imx_header_v3_t)) {
fprintf(stderr, "error writing image hdr\n");
exit(1);
}
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 == DCD ||
img_sp->option == OUTPUT ||
img_sp->option == FLAG ||
img_sp->option == DEVICE ||
img_sp->option == NEW_CONTAINER ||
img_sp->option == PARTITION) {
img_sp++;
continue;/* skip writing to the output file if not an image option */
}
if (img_sp->option == CSF){ /* only pad if its a CSF image */
copy_file(ofd, img_sp->filename, CSF_DATA_SIZE, img_sp->src - ivt_offset);
}
else {
copy_file(ofd, img_sp->filename, 0, img_sp->src - ivt_offset);
}
img_sp++;
}
/* Close output file */
close(ofd);
return 0;
}