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 += sizeof(struct opt_hdr_v1) +
329 (binarye->binary.nargs + 2) * sizeof(uint32_t);
334 #if defined(CONFIG_SYS_U_BOOT_OFFS)
335 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
336 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
337 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
338 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
339 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
342 headersz = CONFIG_SYS_U_BOOT_OFFS;
347 * The payload should be aligned on some reasonable
350 return ALIGN_SUP(headersz, 4096);
353 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
356 struct image_cfg_element *e, *binarye;
357 struct main_hdr_v1 *main_hdr;
364 * Calculate the size of the header and the size of the
367 headersz = image_headersz_v1(params, &hasext);
371 image = malloc(headersz);
373 fprintf(stderr, "Cannot allocate memory for image\n");
377 memset(image, 0, headersz);
379 cur = main_hdr = image;
380 cur += sizeof(struct main_hdr_v1);
382 /* Fill the main header */
383 main_hdr->blocksize =
384 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
385 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
386 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
387 main_hdr->destaddr = cpu_to_le32(params->addr);
388 main_hdr->execaddr = cpu_to_le32(params->ep);
389 main_hdr->srcaddr = cpu_to_le32(headersz);
390 main_hdr->ext = hasext;
391 main_hdr->version = 1;
392 e = image_find_option(IMAGE_CFG_BOOT_FROM);
394 main_hdr->blockid = e->bootfrom;
395 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
397 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
398 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
400 main_hdr->nandbadblklocation = e->nandbadblklocation;
402 binarye = image_find_option(IMAGE_CFG_BINARY);
404 struct opt_hdr_v1 *hdr = cur;
411 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
413 bin = fopen(binarye->binary.file, "r");
415 fprintf(stderr, "Cannot open binary file %s\n",
416 binarye->binary.file);
420 fstat(fileno(bin), &s);
422 binhdrsz = sizeof(struct opt_hdr_v1) +
423 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
427 * The size includes the binary image size, rounded
428 * up to a 4-byte boundary. Plus 4 bytes for the
429 * next-header byte and 3-byte alignment at the end.
431 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
432 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
433 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
435 cur += sizeof(struct opt_hdr_v1);
438 *args = cpu_to_le32(binarye->binary.nargs);
440 for (argi = 0; argi < binarye->binary.nargs; argi++)
441 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
443 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
445 ret = fread(cur, s.st_size, 1, bin);
448 "Could not read binary image %s\n",
449 binarye->binary.file);
455 cur += ALIGN_SUP(s.st_size, 4);
458 * For now, we don't support more than one binary
459 * header, and no other header types are
460 * supported. So, the binary header is necessarily the
463 *((uint32_t *)cur) = 0x00000000;
465 cur += sizeof(uint32_t);
468 /* Calculate and set the header checksum */
469 main_hdr->checksum = image_checksum8(main_hdr, headersz);
475 static int image_create_config_parse_oneline(char *line,
476 struct image_cfg_element *el)
478 char *keyword, *saveptr;
479 char deliminiters[] = " \t";
481 keyword = strtok_r(line, deliminiters, &saveptr);
482 if (!strcmp(keyword, "VERSION")) {
483 char *value = strtok_r(NULL, deliminiters, &saveptr);
484 el->type = IMAGE_CFG_VERSION;
485 el->version = atoi(value);
486 } else if (!strcmp(keyword, "BOOT_FROM")) {
487 char *value = strtok_r(NULL, deliminiters, &saveptr);
488 int ret = image_boot_mode_id(value);
491 "Invalid boot media '%s'\n", value);
494 el->type = IMAGE_CFG_BOOT_FROM;
496 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
497 char *value = strtok_r(NULL, deliminiters, &saveptr);
498 el->type = IMAGE_CFG_NAND_BLKSZ;
499 el->nandblksz = strtoul(value, NULL, 16);
500 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
501 char *value = strtok_r(NULL, deliminiters, &saveptr);
502 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
503 el->nandbadblklocation =
504 strtoul(value, NULL, 16);
505 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
506 char *value = strtok_r(NULL, deliminiters, &saveptr);
507 int ret = image_nand_ecc_mode_id(value);
510 "Invalid NAND ECC mode '%s'\n", value);
513 el->type = IMAGE_CFG_NAND_ECC_MODE;
514 el->nandeccmode = ret;
515 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
516 char *value = strtok_r(NULL, deliminiters, &saveptr);
517 el->type = IMAGE_CFG_NAND_PAGESZ;
518 el->nandpagesz = strtoul(value, NULL, 16);
519 } else if (!strcmp(keyword, "BINARY")) {
520 char *value = strtok_r(NULL, deliminiters, &saveptr);
523 el->type = IMAGE_CFG_BINARY;
524 el->binary.file = strdup(value);
526 value = strtok_r(NULL, deliminiters, &saveptr);
529 el->binary.args[argi] = strtoul(value, NULL, 16);
531 if (argi >= BINARY_MAX_ARGS) {
533 "Too many argument for binary\n");
537 el->binary.nargs = argi;
538 } else if (!strcmp(keyword, "DATA")) {
539 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
540 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
542 if (!value1 || !value2) {
544 "Invalid number of arguments for DATA\n");
548 el->type = IMAGE_CFG_DATA;
549 el->regdata.raddr = strtoul(value1, NULL, 16);
550 el->regdata.rdata = strtoul(value2, NULL, 16);
552 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
559 * Parse the configuration file 'fcfg' into the array of configuration
560 * elements 'image_cfg', and return the number of configuration
561 * elements in 'cfgn'.
563 static int image_create_config_parse(FILE *fcfg)
568 /* Parse the configuration file */
569 while (!feof(fcfg)) {
573 /* Read the current line */
574 memset(buf, 0, sizeof(buf));
575 line = fgets(buf, sizeof(buf), fcfg);
579 /* Ignore useless lines */
580 if (line[0] == '\n' || line[0] == '#')
583 /* Strip final newline */
584 if (line[strlen(line) - 1] == '\n')
585 line[strlen(line) - 1] = 0;
587 /* Parse the current line */
588 ret = image_create_config_parse_oneline(line,
595 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
597 "Too many configuration elements in .cfg file\n");
606 static int image_get_version(void)
608 struct image_cfg_element *e;
610 e = image_find_option(IMAGE_CFG_VERSION);
617 static int image_version_file(const char *input)
623 fcfg = fopen(input, "r");
625 fprintf(stderr, "Could not open input file %s\n", input);
629 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
630 sizeof(struct image_cfg_element));
632 fprintf(stderr, "Cannot allocate memory\n");
638 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
641 ret = image_create_config_parse(fcfg);
648 version = image_get_version();
649 /* Fallback to version 0 is no version is provided in the cfg file */
658 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
659 struct image_tool_params *params)
669 fcfg = fopen(params->imagename, "r");
671 fprintf(stderr, "Could not open input file %s\n",
676 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
677 sizeof(struct image_cfg_element));
679 fprintf(stderr, "Cannot allocate memory\n");
685 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
688 ret = image_create_config_parse(fcfg);
695 /* The MVEBU BootROM does not allow non word aligned payloads */
696 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
698 version = image_get_version();
701 * Fallback to version 0 if no version is provided in the
706 image = image_create_v0(&headersz, params, sbuf->st_size);
710 image = image_create_v1(&headersz, params, sbuf->st_size);
714 fprintf(stderr, "Unsupported version %d\n", version);
720 fprintf(stderr, "Could not create image\n");
727 /* Build and add image checksum header */
729 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
730 size = write(ifd, &checksum, sizeof(uint32_t));
731 if (size != sizeof(uint32_t)) {
732 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
733 params->cmdname, size, params->imagefile);
737 sbuf->st_size += sizeof(uint32_t);
739 /* Finally copy the header into the image area */
740 memcpy(ptr, image, headersz);
745 static void kwbimage_print_header(const void *ptr)
747 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
749 printf("Image Type: MVEBU Boot from %s Image\n",
750 image_boot_mode_name(mhdr->blockid));
751 printf("Image version:%d\n", image_version((void *)ptr));
752 printf("Data Size: ");
753 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
754 printf("Load Address: %08x\n", mhdr->destaddr);
755 printf("Entry Point: %08x\n", mhdr->execaddr);
758 static int kwbimage_check_image_types(uint8_t type)
760 if (type == IH_TYPE_KWBIMAGE)
766 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
767 struct image_tool_params *params)
769 struct main_hdr_v0 *main_hdr;
770 struct ext_hdr_v0 *ext_hdr;
773 main_hdr = (void *)ptr;
774 checksum = image_checksum8(ptr,
775 sizeof(struct main_hdr_v0)
777 if (checksum != main_hdr->checksum)
778 return -FDT_ERR_BADSTRUCTURE;
780 /* Only version 0 extended header has checksum */
781 if (image_version((void *)ptr) == 0) {
782 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
783 checksum = image_checksum8(ext_hdr,
784 sizeof(struct ext_hdr_v0)
786 if (checksum != ext_hdr->checksum)
787 return -FDT_ERR_BADSTRUCTURE;
793 static int kwbimage_generate(struct image_tool_params *params,
794 struct image_type_params *tparams)
800 version = image_version_file(params->imagename);
802 alloc_len = sizeof(struct main_hdr_v0) +
803 sizeof(struct ext_hdr_v0);
805 alloc_len = image_headersz_v1(params, NULL);
808 hdr = malloc(alloc_len);
810 fprintf(stderr, "%s: malloc return failure: %s\n",
811 params->cmdname, strerror(errno));
815 memset(hdr, 0, alloc_len);
816 tparams->header_size = alloc_len;
820 * The resulting image needs to be 4-byte aligned. At least
821 * the Marvell hdrparser tool complains if its unaligned.
822 * By returning 1 here in this function, called via
823 * tparams->vrec_header() in mkimage.c, mkimage will
824 * automatically pad the the resulting image to a 4-byte
831 * Report Error if xflag is set in addition to default
833 static int kwbimage_check_params(struct image_tool_params *params)
835 if (!strlen(params->imagename)) {
836 fprintf(stderr, "Error:%s - Configuration file not specified, "
837 "it is needed for kwbimage generation\n",
842 return (params->dflag && (params->fflag || params->lflag)) ||
843 (params->fflag && (params->dflag || params->lflag)) ||
844 (params->lflag && (params->dflag || params->fflag)) ||
845 (params->xflag) || !(strlen(params->imagename));
849 * kwbimage type parameters definition
853 "Marvell MVEBU Boot Image support",
856 kwbimage_check_params,
857 kwbimage_verify_header,
858 kwbimage_print_header,
861 kwbimage_check_image_types,