2 * Image manipulator for Marvell SoCs
3 * supports Kirkwood, Dove, Armada 370, and Armada XP
5 * (C) Copyright 2013 Thomas Petazzoni
6 * <thomas.petazzoni@free-electrons.com>
8 * SPDX-License-Identifier: GPL-2.0+
10 * Not implemented: support for the register headers and secure
11 * headers in v1 images
14 #include "imagetool.h"
20 #define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
22 /* Structure of the main header, version 0 (Kirkwood, Dove) */
24 uint8_t blockid; /*0 */
25 uint8_t nandeccmode; /*1 */
26 uint16_t nandpagesize; /*2-3 */
27 uint32_t blocksize; /*4-7 */
28 uint32_t rsvd1; /*8-11 */
29 uint32_t srcaddr; /*12-15 */
30 uint32_t destaddr; /*16-19 */
31 uint32_t execaddr; /*20-23 */
32 uint8_t satapiomode; /*24 */
33 uint8_t rsvd3; /*25 */
34 uint16_t ddrinitdelay; /*26-27 */
35 uint16_t rsvd2; /*28-29 */
37 uint8_t checksum; /*31 */
40 struct ext_hdr_v0_reg {
45 #define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
49 uint8_t reserved[0x20 - sizeof(uint32_t)];
50 struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
55 /* Structure of the main header, version 1 (Armada 370, Armada XP) */
57 uint8_t blockid; /* 0 */
58 uint8_t reserved1; /* 1 */
59 uint16_t reserved2; /* 2-3 */
60 uint32_t blocksize; /* 4-7 */
61 uint8_t version; /* 8 */
62 uint8_t headersz_msb; /* 9 */
63 uint16_t headersz_lsb; /* A-B */
64 uint32_t srcaddr; /* C-F */
65 uint32_t destaddr; /* 10-13 */
66 uint32_t execaddr; /* 14-17 */
67 uint8_t reserved3; /* 18 */
68 uint8_t nandblocksize; /* 19 */
69 uint8_t nandbadblklocation; /* 1A */
70 uint8_t reserved4; /* 1B */
71 uint16_t reserved5; /* 1C-1D */
73 uint8_t checksum; /* 1F */
77 * Header for the optional headers, version 1 (Armada 370, Armada XP)
82 uint16_t headersz_lsb;
87 * Various values for the opt_hdr_v1->headertype field, describing the
88 * different types of optional headers. The "secure" header contains
89 * informations related to secure boot (encryption keys, etc.). The
90 * "binary" header contains ARM binary code to be executed prior to
91 * executing the main payload (usually the bootloader). This is
92 * typically used to execute DDR3 training code. The "register" header
93 * allows to describe a set of (address, value) tuples that are
94 * generally used to configure the DRAM controller.
96 #define OPT_HDR_V1_SECURE_TYPE 0x1
97 #define OPT_HDR_V1_BINARY_TYPE 0x2
98 #define OPT_HDR_V1_REGISTER_TYPE 0x3
100 #define KWBHEADER_V1_SIZE(hdr) \
101 (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
103 static struct image_cfg_element *image_cfg;
111 struct boot_mode boot_modes[] = {
122 struct nand_ecc_mode {
127 struct nand_ecc_mode nand_ecc_modes[] = {
131 { 0x03, "disabled" },
135 /* Used to identify an undefined execution or destination address */
136 #define ADDR_INVALID ((uint32_t)-1)
138 #define BINARY_MAX_ARGS 8
140 /* In-memory representation of a line of the configuration file */
141 struct image_cfg_element {
143 IMAGE_CFG_VERSION = 0x1,
147 IMAGE_CFG_NAND_BLKSZ,
148 IMAGE_CFG_NAND_BADBLK_LOCATION,
149 IMAGE_CFG_NAND_ECC_MODE,
150 IMAGE_CFG_NAND_PAGESZ,
156 unsigned int version;
157 unsigned int bootfrom;
160 unsigned int args[BINARY_MAX_ARGS];
164 unsigned int dstaddr;
165 unsigned int execaddr;
166 unsigned int nandblksz;
167 unsigned int nandbadblklocation;
168 unsigned int nandeccmode;
169 unsigned int nandpagesz;
170 struct ext_hdr_v0_reg regdata;
174 #define IMAGE_CFG_ELEMENT_MAX 256
177 * Byte 8 of the image header contains the version number. In the v0
178 * header, byte 8 was reserved, and always set to 0. In the v1 header,
179 * byte 8 has been changed to a proper field, set to 1.
181 static unsigned int image_version(void *header)
183 unsigned char *ptr = header;
188 * Utility functions to manipulate boot mode and ecc modes (convert
189 * them back and forth between description strings and the
190 * corresponding numerical identifiers).
193 static const char *image_boot_mode_name(unsigned int id)
196 for (i = 0; boot_modes[i].name; i++)
197 if (boot_modes[i].id == id)
198 return boot_modes[i].name;
202 int image_boot_mode_id(const char *boot_mode_name)
205 for (i = 0; boot_modes[i].name; i++)
206 if (!strcmp(boot_modes[i].name, boot_mode_name))
207 return boot_modes[i].id;
212 int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
215 for (i = 0; nand_ecc_modes[i].name; i++)
216 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
217 return nand_ecc_modes[i].id;
221 static struct image_cfg_element *
222 image_find_option(unsigned int optiontype)
226 for (i = 0; i < cfgn; i++) {
227 if (image_cfg[i].type == optiontype)
228 return &image_cfg[i];
235 image_count_options(unsigned int optiontype)
238 unsigned int count = 0;
240 for (i = 0; i < cfgn; i++)
241 if (image_cfg[i].type == optiontype)
248 * Compute a 8-bit checksum of a memory area. This algorithm follows
249 * the requirements of the Marvell SoC BootROM specifications.
251 static uint8_t image_checksum8(void *start, uint32_t len)
256 /* check len and return zero checksum if invalid */
268 static uint32_t image_checksum32(void *start, uint32_t len)
273 /* check len and return zero checksum if invalid */
277 if (len % sizeof(uint32_t)) {
278 fprintf(stderr, "Length %d is not in multiple of %zu\n",
279 len, sizeof(uint32_t));
286 len -= sizeof(uint32_t);
292 static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
295 struct image_cfg_element *e;
297 struct main_hdr_v0 *main_hdr;
298 struct ext_hdr_v0 *ext_hdr;
303 * Calculate the size of the header and the size of the
306 headersz = sizeof(struct main_hdr_v0);
308 if (image_count_options(IMAGE_CFG_DATA) > 0) {
310 headersz += sizeof(struct ext_hdr_v0);
313 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
314 fprintf(stderr, "More than one payload, not possible\n");
318 image = malloc(headersz);
320 fprintf(stderr, "Cannot allocate memory for image\n");
324 memset(image, 0, headersz);
328 /* Fill in the main header */
329 main_hdr->blocksize = payloadsz + sizeof(uint32_t) - headersz;
330 main_hdr->srcaddr = headersz;
331 main_hdr->ext = has_ext;
332 main_hdr->destaddr = params->addr;
333 main_hdr->execaddr = params->ep;
335 e = image_find_option(IMAGE_CFG_BOOT_FROM);
337 main_hdr->blockid = e->bootfrom;
338 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
340 main_hdr->nandeccmode = e->nandeccmode;
341 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
343 main_hdr->nandpagesize = e->nandpagesz;
344 main_hdr->checksum = image_checksum8(image,
345 sizeof(struct main_hdr_v0));
347 /* Generate the ext header */
351 ext_hdr = image + sizeof(struct main_hdr_v0);
352 ext_hdr->offset = 0x40;
354 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
355 e = &image_cfg[cfgi];
356 if (e->type != IMAGE_CFG_DATA)
359 ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
360 ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
364 ext_hdr->checksum = image_checksum8(ext_hdr,
365 sizeof(struct ext_hdr_v0));
372 static size_t image_headersz_v1(struct image_tool_params *params,
375 struct image_cfg_element *binarye;
380 * Calculate the size of the header and the size of the
383 headersz = sizeof(struct main_hdr_v1);
385 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
386 fprintf(stderr, "More than one binary blob, not supported\n");
390 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
391 fprintf(stderr, "More than one payload, not possible\n");
395 binarye = image_find_option(IMAGE_CFG_BINARY);
399 ret = stat(binarye->binary.file, &s);
404 memset(cwd, 0, sizeof(cwd));
405 if (!getcwd(cwd, sizeof(cwd))) {
406 dir = "current working directory";
407 perror("getcwd() failed");
411 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
412 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
413 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
414 binarye->binary.file, dir);
418 headersz += s.st_size +
419 binarye->binary.nargs * sizeof(unsigned int);
424 #if defined(CONFIG_SYS_U_BOOT_OFFS)
425 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
426 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
427 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
428 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
429 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
432 headersz = CONFIG_SYS_U_BOOT_OFFS;
437 * The payload should be aligned on some reasonable
440 return ALIGN_SUP(headersz, 4096);
443 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
446 struct image_cfg_element *e, *binarye;
447 struct main_hdr_v1 *main_hdr;
454 * Calculate the size of the header and the size of the
457 headersz = image_headersz_v1(params, &hasext);
461 image = malloc(headersz);
463 fprintf(stderr, "Cannot allocate memory for image\n");
467 memset(image, 0, headersz);
469 cur = main_hdr = image;
470 cur += sizeof(struct main_hdr_v1);
472 /* Fill the main header */
473 main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t);
474 main_hdr->headersz_lsb = headersz & 0xFFFF;
475 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
476 main_hdr->destaddr = params->addr;
477 main_hdr->execaddr = params->ep;
478 main_hdr->srcaddr = headersz;
479 main_hdr->ext = hasext;
480 main_hdr->version = 1;
481 e = image_find_option(IMAGE_CFG_BOOT_FROM);
483 main_hdr->blockid = e->bootfrom;
484 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
486 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
487 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
489 main_hdr->nandbadblklocation = e->nandbadblklocation;
491 binarye = image_find_option(IMAGE_CFG_BINARY);
493 struct opt_hdr_v1 *hdr = cur;
500 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
502 bin = fopen(binarye->binary.file, "r");
504 fprintf(stderr, "Cannot open binary file %s\n",
505 binarye->binary.file);
509 fstat(fileno(bin), &s);
511 binhdrsz = sizeof(struct opt_hdr_v1) +
512 (binarye->binary.nargs + 1) * sizeof(unsigned int) +
514 binhdrsz = ALIGN_SUP(binhdrsz, 32);
515 hdr->headersz_lsb = binhdrsz & 0xFFFF;
516 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
518 cur += sizeof(struct opt_hdr_v1);
521 *args = binarye->binary.nargs;
523 for (argi = 0; argi < binarye->binary.nargs; argi++)
524 args[argi] = binarye->binary.args[argi];
526 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
528 ret = fread(cur, s.st_size, 1, bin);
531 "Could not read binary image %s\n",
532 binarye->binary.file);
541 * For now, we don't support more than one binary
542 * header, and no other header types are
543 * supported. So, the binary header is necessarily the
546 *((unsigned char *)cur) = 0;
548 cur += sizeof(uint32_t);
551 /* Calculate and set the header checksum */
552 main_hdr->checksum = image_checksum8(main_hdr, headersz);
558 static int image_create_config_parse_oneline(char *line,
559 struct image_cfg_element *el)
561 char *keyword, *saveptr;
562 char deliminiters[] = " \t";
564 keyword = strtok_r(line, deliminiters, &saveptr);
565 if (!strcmp(keyword, "VERSION")) {
566 char *value = strtok_r(NULL, deliminiters, &saveptr);
567 el->type = IMAGE_CFG_VERSION;
568 el->version = atoi(value);
569 } else if (!strcmp(keyword, "BOOT_FROM")) {
570 char *value = strtok_r(NULL, deliminiters, &saveptr);
571 int ret = image_boot_mode_id(value);
574 "Invalid boot media '%s'\n", value);
577 el->type = IMAGE_CFG_BOOT_FROM;
579 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
580 char *value = strtok_r(NULL, deliminiters, &saveptr);
581 el->type = IMAGE_CFG_NAND_BLKSZ;
582 el->nandblksz = strtoul(value, NULL, 16);
583 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
584 char *value = strtok_r(NULL, deliminiters, &saveptr);
585 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
586 el->nandbadblklocation =
587 strtoul(value, NULL, 16);
588 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
589 char *value = strtok_r(NULL, deliminiters, &saveptr);
590 int ret = image_nand_ecc_mode_id(value);
593 "Invalid NAND ECC mode '%s'\n", value);
596 el->type = IMAGE_CFG_NAND_ECC_MODE;
597 el->nandeccmode = ret;
598 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
599 char *value = strtok_r(NULL, deliminiters, &saveptr);
600 el->type = IMAGE_CFG_NAND_PAGESZ;
601 el->nandpagesz = strtoul(value, NULL, 16);
602 } else if (!strcmp(keyword, "BINARY")) {
603 char *value = strtok_r(NULL, deliminiters, &saveptr);
606 el->type = IMAGE_CFG_BINARY;
607 el->binary.file = strdup(value);
609 value = strtok_r(NULL, deliminiters, &saveptr);
612 el->binary.args[argi] = strtoul(value, NULL, 16);
614 if (argi >= BINARY_MAX_ARGS) {
616 "Too many argument for binary\n");
620 el->binary.nargs = argi;
621 } else if (!strcmp(keyword, "DATA")) {
622 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
623 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
625 if (!value1 || !value2) {
627 "Invalid number of arguments for DATA\n");
631 el->type = IMAGE_CFG_DATA;
632 el->regdata.raddr = strtoul(value1, NULL, 16);
633 el->regdata.rdata = strtoul(value2, NULL, 16);
635 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
642 * Parse the configuration file 'fcfg' into the array of configuration
643 * elements 'image_cfg', and return the number of configuration
644 * elements in 'cfgn'.
646 static int image_create_config_parse(FILE *fcfg)
651 /* Parse the configuration file */
652 while (!feof(fcfg)) {
656 /* Read the current line */
657 memset(buf, 0, sizeof(buf));
658 line = fgets(buf, sizeof(buf), fcfg);
662 /* Ignore useless lines */
663 if (line[0] == '\n' || line[0] == '#')
666 /* Strip final newline */
667 if (line[strlen(line) - 1] == '\n')
668 line[strlen(line) - 1] = 0;
670 /* Parse the current line */
671 ret = image_create_config_parse_oneline(line,
678 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
680 "Too many configuration elements in .cfg file\n");
689 static int image_get_version(void)
691 struct image_cfg_element *e;
693 e = image_find_option(IMAGE_CFG_VERSION);
700 static int image_version_file(const char *input)
706 fcfg = fopen(input, "r");
708 fprintf(stderr, "Could not open input file %s\n", input);
712 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
713 sizeof(struct image_cfg_element));
715 fprintf(stderr, "Cannot allocate memory\n");
721 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
724 ret = image_create_config_parse(fcfg);
731 version = image_get_version();
732 /* Fallback to version 0 is no version is provided in the cfg file */
741 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
742 struct image_tool_params *params)
752 fcfg = fopen(params->imagename, "r");
754 fprintf(stderr, "Could not open input file %s\n",
759 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
760 sizeof(struct image_cfg_element));
762 fprintf(stderr, "Cannot allocate memory\n");
768 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
771 ret = image_create_config_parse(fcfg);
778 version = image_get_version();
781 * Fallback to version 0 if no version is provided in the
786 image = image_create_v0(&headersz, params, sbuf->st_size);
790 image = image_create_v1(&headersz, params, sbuf->st_size);
794 fprintf(stderr, "Unsupported version %d\n", version);
800 fprintf(stderr, "Could not create image\n");
807 /* Build and add image checksum header */
808 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
809 size = write(ifd, &checksum, sizeof(uint32_t));
810 if (size != sizeof(uint32_t)) {
811 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
812 params->cmdname, size, params->imagefile);
816 sbuf->st_size += sizeof(uint32_t);
818 /* Finally copy the header into the image area */
819 memcpy(ptr, image, headersz);
824 static void kwbimage_print_header(const void *ptr)
826 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
828 printf("Image Type: MVEBU Boot from %s Image\n",
829 image_boot_mode_name(mhdr->blockid));
830 printf("Image version:%d\n", image_version((void *)ptr));
831 printf("Data Size: ");
832 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
833 printf("Load Address: %08x\n", mhdr->destaddr);
834 printf("Entry Point: %08x\n", mhdr->execaddr);
837 static int kwbimage_check_image_types(uint8_t type)
839 if (type == IH_TYPE_KWBIMAGE)
845 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
846 struct image_tool_params *params)
848 struct main_hdr_v0 *main_hdr;
849 struct ext_hdr_v0 *ext_hdr;
852 main_hdr = (void *)ptr;
853 checksum = image_checksum8(ptr,
854 sizeof(struct main_hdr_v0)
856 if (checksum != main_hdr->checksum)
857 return -FDT_ERR_BADSTRUCTURE;
859 /* Only version 0 extended header has checksum */
860 if (image_version((void *)ptr) == 0) {
861 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
862 checksum = image_checksum8(ext_hdr,
863 sizeof(struct ext_hdr_v0)
865 if (checksum != ext_hdr->checksum)
866 return -FDT_ERR_BADSTRUCTURE;
872 static int kwbimage_generate(struct image_tool_params *params,
873 struct image_type_params *tparams)
879 version = image_version_file(params->imagename);
881 alloc_len = sizeof(struct main_hdr_v0) +
882 sizeof(struct ext_hdr_v0);
884 alloc_len = image_headersz_v1(params, NULL);
887 hdr = malloc(alloc_len);
889 fprintf(stderr, "%s: malloc return failure: %s\n",
890 params->cmdname, strerror(errno));
894 memset(hdr, 0, alloc_len);
895 tparams->header_size = alloc_len;
902 * Report Error if xflag is set in addition to default
904 static int kwbimage_check_params(struct image_tool_params *params)
906 if (!strlen(params->imagename)) {
907 fprintf(stderr, "Error:%s - Configuration file not specified, "
908 "it is needed for kwbimage generation\n",
913 return (params->dflag && (params->fflag || params->lflag)) ||
914 (params->fflag && (params->dflag || params->lflag)) ||
915 (params->lflag && (params->dflag || params->fflag)) ||
916 (params->xflag) || !(strlen(params->imagename));
920 * kwbimage type parameters definition
924 "Marvell MVEBU Boot Image support",
927 kwbimage_check_params,
928 kwbimage_verify_header,
929 kwbimage_print_header,
932 kwbimage_check_image_types,