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 static struct image_cfg_element *image_cfg;
28 struct boot_mode boot_modes[] = {
39 struct nand_ecc_mode {
44 struct nand_ecc_mode nand_ecc_modes[] = {
52 /* Used to identify an undefined execution or destination address */
53 #define ADDR_INVALID ((uint32_t)-1)
55 #define BINARY_MAX_ARGS 8
57 /* In-memory representation of a line of the configuration file */
58 struct image_cfg_element {
60 IMAGE_CFG_VERSION = 0x1,
65 IMAGE_CFG_NAND_BADBLK_LOCATION,
66 IMAGE_CFG_NAND_ECC_MODE,
67 IMAGE_CFG_NAND_PAGESZ,
74 unsigned int bootfrom;
77 unsigned int args[BINARY_MAX_ARGS];
82 unsigned int execaddr;
83 unsigned int nandblksz;
84 unsigned int nandbadblklocation;
85 unsigned int nandeccmode;
86 unsigned int nandpagesz;
87 struct ext_hdr_v0_reg regdata;
91 #define IMAGE_CFG_ELEMENT_MAX 256
94 * Utility functions to manipulate boot mode and ecc modes (convert
95 * them back and forth between description strings and the
96 * corresponding numerical identifiers).
99 static const char *image_boot_mode_name(unsigned int id)
102 for (i = 0; boot_modes[i].name; i++)
103 if (boot_modes[i].id == id)
104 return boot_modes[i].name;
108 int image_boot_mode_id(const char *boot_mode_name)
111 for (i = 0; boot_modes[i].name; i++)
112 if (!strcmp(boot_modes[i].name, boot_mode_name))
113 return boot_modes[i].id;
118 int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
121 for (i = 0; nand_ecc_modes[i].name; i++)
122 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
123 return nand_ecc_modes[i].id;
127 static struct image_cfg_element *
128 image_find_option(unsigned int optiontype)
132 for (i = 0; i < cfgn; i++) {
133 if (image_cfg[i].type == optiontype)
134 return &image_cfg[i];
141 image_count_options(unsigned int optiontype)
144 unsigned int count = 0;
146 for (i = 0; i < cfgn; i++)
147 if (image_cfg[i].type == optiontype)
154 * Compute a 8-bit checksum of a memory area. This algorithm follows
155 * the requirements of the Marvell SoC BootROM specifications.
157 static uint8_t image_checksum8(void *start, uint32_t len)
162 /* check len and return zero checksum if invalid */
174 static uint32_t image_checksum32(void *start, uint32_t len)
179 /* check len and return zero checksum if invalid */
183 if (len % sizeof(uint32_t)) {
184 fprintf(stderr, "Length %d is not in multiple of %zu\n",
185 len, sizeof(uint32_t));
192 len -= sizeof(uint32_t);
198 static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
201 struct image_cfg_element *e;
203 struct main_hdr_v0 *main_hdr;
204 struct ext_hdr_v0 *ext_hdr;
209 * Calculate the size of the header and the size of the
212 headersz = sizeof(struct main_hdr_v0);
214 if (image_count_options(IMAGE_CFG_DATA) > 0) {
216 headersz += sizeof(struct ext_hdr_v0);
219 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
220 fprintf(stderr, "More than one payload, not possible\n");
224 image = malloc(headersz);
226 fprintf(stderr, "Cannot allocate memory for image\n");
230 memset(image, 0, headersz);
234 /* Fill in the main header */
235 main_hdr->blocksize =
236 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
237 main_hdr->srcaddr = cpu_to_le32(headersz);
238 main_hdr->ext = has_ext;
239 main_hdr->destaddr = cpu_to_le32(params->addr);
240 main_hdr->execaddr = cpu_to_le32(params->ep);
242 e = image_find_option(IMAGE_CFG_BOOT_FROM);
244 main_hdr->blockid = e->bootfrom;
245 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
247 main_hdr->nandeccmode = e->nandeccmode;
248 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
250 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
251 main_hdr->checksum = image_checksum8(image,
252 sizeof(struct main_hdr_v0));
254 /* Generate the ext header */
258 ext_hdr = image + sizeof(struct main_hdr_v0);
259 ext_hdr->offset = cpu_to_le32(0x40);
261 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
262 e = &image_cfg[cfgi];
263 if (e->type != IMAGE_CFG_DATA)
266 ext_hdr->rcfg[datai].raddr =
267 cpu_to_le32(e->regdata.raddr);
268 ext_hdr->rcfg[datai].rdata =
269 cpu_to_le32(e->regdata.rdata);
273 ext_hdr->checksum = image_checksum8(ext_hdr,
274 sizeof(struct ext_hdr_v0));
281 static size_t image_headersz_v1(struct image_tool_params *params,
284 struct image_cfg_element *binarye;
289 * Calculate the size of the header and the size of the
292 headersz = sizeof(struct main_hdr_v1);
294 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
295 fprintf(stderr, "More than one binary blob, not supported\n");
299 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
300 fprintf(stderr, "More than one payload, not possible\n");
304 binarye = image_find_option(IMAGE_CFG_BINARY);
308 ret = stat(binarye->binary.file, &s);
313 memset(cwd, 0, sizeof(cwd));
314 if (!getcwd(cwd, sizeof(cwd))) {
315 dir = "current working directory";
316 perror("getcwd() failed");
320 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
321 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
322 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
323 binarye->binary.file, dir);
327 headersz += s.st_size +
328 binarye->binary.nargs * sizeof(unsigned int);
333 #if defined(CONFIG_SYS_U_BOOT_OFFS)
334 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
335 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
336 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
337 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
338 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
341 headersz = CONFIG_SYS_U_BOOT_OFFS;
346 * The payload should be aligned on some reasonable
349 return ALIGN_SUP(headersz, 4096);
352 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
355 struct image_cfg_element *e, *binarye;
356 struct main_hdr_v1 *main_hdr;
363 * Calculate the size of the header and the size of the
366 headersz = image_headersz_v1(params, &hasext);
370 image = malloc(headersz);
372 fprintf(stderr, "Cannot allocate memory for image\n");
376 memset(image, 0, headersz);
378 cur = main_hdr = image;
379 cur += sizeof(struct main_hdr_v1);
381 /* Fill the main header */
382 main_hdr->blocksize =
383 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
384 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
385 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
386 main_hdr->destaddr = cpu_to_le32(params->addr);
387 main_hdr->execaddr = cpu_to_le32(params->ep);
388 main_hdr->srcaddr = cpu_to_le32(headersz);
389 main_hdr->ext = hasext;
390 main_hdr->version = 1;
391 e = image_find_option(IMAGE_CFG_BOOT_FROM);
393 main_hdr->blockid = e->bootfrom;
394 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
396 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
397 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
399 main_hdr->nandbadblklocation = e->nandbadblklocation;
401 binarye = image_find_option(IMAGE_CFG_BINARY);
403 struct opt_hdr_v1 *hdr = cur;
410 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
412 bin = fopen(binarye->binary.file, "r");
414 fprintf(stderr, "Cannot open binary file %s\n",
415 binarye->binary.file);
419 fstat(fileno(bin), &s);
421 binhdrsz = sizeof(struct opt_hdr_v1) +
422 (binarye->binary.nargs + 1) * sizeof(unsigned int) +
426 * The size includes the binary image size, rounded
427 * up to a 4-byte boundary. Plus 4 bytes for the
428 * next-header byte and 3-byte alignment at the end.
430 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
431 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
432 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
434 cur += sizeof(struct opt_hdr_v1);
437 *args = cpu_to_le32(binarye->binary.nargs);
439 for (argi = 0; argi < binarye->binary.nargs; argi++)
440 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
442 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
444 ret = fread(cur, s.st_size, 1, bin);
447 "Could not read binary image %s\n",
448 binarye->binary.file);
454 cur += ALIGN_SUP(s.st_size, 4);
457 * For now, we don't support more than one binary
458 * header, and no other header types are
459 * supported. So, the binary header is necessarily the
462 *((uint32_t *)cur) = 0x00000000;
464 cur += sizeof(uint32_t);
467 /* Calculate and set the header checksum */
468 main_hdr->checksum = image_checksum8(main_hdr, headersz);
474 static int image_create_config_parse_oneline(char *line,
475 struct image_cfg_element *el)
477 char *keyword, *saveptr;
478 char deliminiters[] = " \t";
480 keyword = strtok_r(line, deliminiters, &saveptr);
481 if (!strcmp(keyword, "VERSION")) {
482 char *value = strtok_r(NULL, deliminiters, &saveptr);
483 el->type = IMAGE_CFG_VERSION;
484 el->version = atoi(value);
485 } else if (!strcmp(keyword, "BOOT_FROM")) {
486 char *value = strtok_r(NULL, deliminiters, &saveptr);
487 int ret = image_boot_mode_id(value);
490 "Invalid boot media '%s'\n", value);
493 el->type = IMAGE_CFG_BOOT_FROM;
495 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
496 char *value = strtok_r(NULL, deliminiters, &saveptr);
497 el->type = IMAGE_CFG_NAND_BLKSZ;
498 el->nandblksz = strtoul(value, NULL, 16);
499 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
500 char *value = strtok_r(NULL, deliminiters, &saveptr);
501 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
502 el->nandbadblklocation =
503 strtoul(value, NULL, 16);
504 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
505 char *value = strtok_r(NULL, deliminiters, &saveptr);
506 int ret = image_nand_ecc_mode_id(value);
509 "Invalid NAND ECC mode '%s'\n", value);
512 el->type = IMAGE_CFG_NAND_ECC_MODE;
513 el->nandeccmode = ret;
514 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
515 char *value = strtok_r(NULL, deliminiters, &saveptr);
516 el->type = IMAGE_CFG_NAND_PAGESZ;
517 el->nandpagesz = strtoul(value, NULL, 16);
518 } else if (!strcmp(keyword, "BINARY")) {
519 char *value = strtok_r(NULL, deliminiters, &saveptr);
522 el->type = IMAGE_CFG_BINARY;
523 el->binary.file = strdup(value);
525 value = strtok_r(NULL, deliminiters, &saveptr);
528 el->binary.args[argi] = strtoul(value, NULL, 16);
530 if (argi >= BINARY_MAX_ARGS) {
532 "Too many argument for binary\n");
536 el->binary.nargs = argi;
537 } else if (!strcmp(keyword, "DATA")) {
538 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
539 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
541 if (!value1 || !value2) {
543 "Invalid number of arguments for DATA\n");
547 el->type = IMAGE_CFG_DATA;
548 el->regdata.raddr = strtoul(value1, NULL, 16);
549 el->regdata.rdata = strtoul(value2, NULL, 16);
551 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
558 * Parse the configuration file 'fcfg' into the array of configuration
559 * elements 'image_cfg', and return the number of configuration
560 * elements in 'cfgn'.
562 static int image_create_config_parse(FILE *fcfg)
567 /* Parse the configuration file */
568 while (!feof(fcfg)) {
572 /* Read the current line */
573 memset(buf, 0, sizeof(buf));
574 line = fgets(buf, sizeof(buf), fcfg);
578 /* Ignore useless lines */
579 if (line[0] == '\n' || line[0] == '#')
582 /* Strip final newline */
583 if (line[strlen(line) - 1] == '\n')
584 line[strlen(line) - 1] = 0;
586 /* Parse the current line */
587 ret = image_create_config_parse_oneline(line,
594 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
596 "Too many configuration elements in .cfg file\n");
605 static int image_get_version(void)
607 struct image_cfg_element *e;
609 e = image_find_option(IMAGE_CFG_VERSION);
616 static int image_version_file(const char *input)
622 fcfg = fopen(input, "r");
624 fprintf(stderr, "Could not open input file %s\n", input);
628 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
629 sizeof(struct image_cfg_element));
631 fprintf(stderr, "Cannot allocate memory\n");
637 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
640 ret = image_create_config_parse(fcfg);
647 version = image_get_version();
648 /* Fallback to version 0 is no version is provided in the cfg file */
657 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
658 struct image_tool_params *params)
668 fcfg = fopen(params->imagename, "r");
670 fprintf(stderr, "Could not open input file %s\n",
675 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
676 sizeof(struct image_cfg_element));
678 fprintf(stderr, "Cannot allocate memory\n");
684 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
687 ret = image_create_config_parse(fcfg);
694 /* The MVEBU BootROM does not allow non word aligned payloads */
695 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
697 version = image_get_version();
700 * Fallback to version 0 if no version is provided in the
705 image = image_create_v0(&headersz, params, sbuf->st_size);
709 image = image_create_v1(&headersz, params, sbuf->st_size);
713 fprintf(stderr, "Unsupported version %d\n", version);
719 fprintf(stderr, "Could not create image\n");
726 /* Build and add image checksum header */
728 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
729 size = write(ifd, &checksum, sizeof(uint32_t));
730 if (size != sizeof(uint32_t)) {
731 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
732 params->cmdname, size, params->imagefile);
736 sbuf->st_size += sizeof(uint32_t);
738 /* Finally copy the header into the image area */
739 memcpy(ptr, image, headersz);
744 static void kwbimage_print_header(const void *ptr)
746 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
748 printf("Image Type: MVEBU Boot from %s Image\n",
749 image_boot_mode_name(mhdr->blockid));
750 printf("Image version:%d\n", image_version((void *)ptr));
751 printf("Data Size: ");
752 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
753 printf("Load Address: %08x\n", mhdr->destaddr);
754 printf("Entry Point: %08x\n", mhdr->execaddr);
757 static int kwbimage_check_image_types(uint8_t type)
759 if (type == IH_TYPE_KWBIMAGE)
765 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
766 struct image_tool_params *params)
768 struct main_hdr_v0 *main_hdr;
769 struct ext_hdr_v0 *ext_hdr;
772 main_hdr = (void *)ptr;
773 checksum = image_checksum8(ptr,
774 sizeof(struct main_hdr_v0)
776 if (checksum != main_hdr->checksum)
777 return -FDT_ERR_BADSTRUCTURE;
779 /* Only version 0 extended header has checksum */
780 if (image_version((void *)ptr) == 0) {
781 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
782 checksum = image_checksum8(ext_hdr,
783 sizeof(struct ext_hdr_v0)
785 if (checksum != ext_hdr->checksum)
786 return -FDT_ERR_BADSTRUCTURE;
792 static int kwbimage_generate(struct image_tool_params *params,
793 struct image_type_params *tparams)
799 version = image_version_file(params->imagename);
801 alloc_len = sizeof(struct main_hdr_v0) +
802 sizeof(struct ext_hdr_v0);
804 alloc_len = image_headersz_v1(params, NULL);
807 hdr = malloc(alloc_len);
809 fprintf(stderr, "%s: malloc return failure: %s\n",
810 params->cmdname, strerror(errno));
814 memset(hdr, 0, alloc_len);
815 tparams->header_size = alloc_len;
819 * The resulting image needs to be 4-byte aligned. At least
820 * the Marvell hdrparser tool complains if its unaligned.
821 * By returning 1 here in this function, called via
822 * tparams->vrec_header() in mkimage.c, mkimage will
823 * automatically pad the the resulting image to a 4-byte
830 * Report Error if xflag is set in addition to default
832 static int kwbimage_check_params(struct image_tool_params *params)
834 if (!strlen(params->imagename)) {
835 fprintf(stderr, "Error:%s - Configuration file not specified, "
836 "it is needed for kwbimage generation\n",
841 return (params->dflag && (params->fflag || params->lflag)) ||
842 (params->fflag && (params->dflag || params->lflag)) ||
843 (params->lflag && (params->dflag || params->fflag)) ||
844 (params->xflag) || !(strlen(params->imagename));
848 * kwbimage type parameters definition
852 "Marvell MVEBU Boot Image support",
855 kwbimage_check_params,
856 kwbimage_verify_header,
857 kwbimage_print_header,
860 kwbimage_check_image_types,