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,
76 unsigned int bootfrom;
79 unsigned int args[BINARY_MAX_ARGS];
84 unsigned int execaddr;
85 unsigned int nandblksz;
86 unsigned int nandbadblklocation;
87 unsigned int nandeccmode;
88 unsigned int nandpagesz;
89 struct ext_hdr_v0_reg regdata;
90 unsigned int baudrate;
95 #define IMAGE_CFG_ELEMENT_MAX 256
98 * Utility functions to manipulate boot mode and ecc modes (convert
99 * them back and forth between description strings and the
100 * corresponding numerical identifiers).
103 static const char *image_boot_mode_name(unsigned int id)
106 for (i = 0; boot_modes[i].name; i++)
107 if (boot_modes[i].id == id)
108 return boot_modes[i].name;
112 int image_boot_mode_id(const char *boot_mode_name)
115 for (i = 0; boot_modes[i].name; i++)
116 if (!strcmp(boot_modes[i].name, boot_mode_name))
117 return boot_modes[i].id;
122 int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
125 for (i = 0; nand_ecc_modes[i].name; i++)
126 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
127 return nand_ecc_modes[i].id;
131 static struct image_cfg_element *
132 image_find_option(unsigned int optiontype)
136 for (i = 0; i < cfgn; i++) {
137 if (image_cfg[i].type == optiontype)
138 return &image_cfg[i];
145 image_count_options(unsigned int optiontype)
148 unsigned int count = 0;
150 for (i = 0; i < cfgn; i++)
151 if (image_cfg[i].type == optiontype)
158 * Compute a 8-bit checksum of a memory area. This algorithm follows
159 * the requirements of the Marvell SoC BootROM specifications.
161 static uint8_t image_checksum8(void *start, uint32_t len)
166 /* check len and return zero checksum if invalid */
178 static uint32_t image_checksum32(void *start, uint32_t len)
183 /* check len and return zero checksum if invalid */
187 if (len % sizeof(uint32_t)) {
188 fprintf(stderr, "Length %d is not in multiple of %zu\n",
189 len, sizeof(uint32_t));
196 len -= sizeof(uint32_t);
202 static uint8_t baudrate_to_option(unsigned int baudrate)
206 return MAIN_HDR_V1_OPT_BAUD_2400;
208 return MAIN_HDR_V1_OPT_BAUD_4800;
210 return MAIN_HDR_V1_OPT_BAUD_9600;
212 return MAIN_HDR_V1_OPT_BAUD_19200;
214 return MAIN_HDR_V1_OPT_BAUD_38400;
216 return MAIN_HDR_V1_OPT_BAUD_57600;
218 return MAIN_HDR_V1_OPT_BAUD_115200;
220 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
224 static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
227 struct image_cfg_element *e;
229 struct main_hdr_v0 *main_hdr;
230 struct ext_hdr_v0 *ext_hdr;
235 * Calculate the size of the header and the size of the
238 headersz = sizeof(struct main_hdr_v0);
240 if (image_count_options(IMAGE_CFG_DATA) > 0) {
242 headersz += sizeof(struct ext_hdr_v0);
245 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
246 fprintf(stderr, "More than one payload, not possible\n");
250 image = malloc(headersz);
252 fprintf(stderr, "Cannot allocate memory for image\n");
256 memset(image, 0, headersz);
260 /* Fill in the main header */
261 main_hdr->blocksize =
262 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
263 main_hdr->srcaddr = cpu_to_le32(headersz);
264 main_hdr->ext = has_ext;
265 main_hdr->destaddr = cpu_to_le32(params->addr);
266 main_hdr->execaddr = cpu_to_le32(params->ep);
268 e = image_find_option(IMAGE_CFG_BOOT_FROM);
270 main_hdr->blockid = e->bootfrom;
271 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
273 main_hdr->nandeccmode = e->nandeccmode;
274 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
276 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
277 main_hdr->checksum = image_checksum8(image,
278 sizeof(struct main_hdr_v0));
280 /* Generate the ext header */
284 ext_hdr = image + sizeof(struct main_hdr_v0);
285 ext_hdr->offset = cpu_to_le32(0x40);
287 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
288 e = &image_cfg[cfgi];
289 if (e->type != IMAGE_CFG_DATA)
292 ext_hdr->rcfg[datai].raddr =
293 cpu_to_le32(e->regdata.raddr);
294 ext_hdr->rcfg[datai].rdata =
295 cpu_to_le32(e->regdata.rdata);
299 ext_hdr->checksum = image_checksum8(ext_hdr,
300 sizeof(struct ext_hdr_v0));
307 static size_t image_headersz_v1(struct image_tool_params *params,
310 struct image_cfg_element *binarye;
315 * Calculate the size of the header and the size of the
318 headersz = sizeof(struct main_hdr_v1);
320 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
321 fprintf(stderr, "More than one binary blob, not supported\n");
325 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
326 fprintf(stderr, "More than one payload, not possible\n");
330 binarye = image_find_option(IMAGE_CFG_BINARY);
334 ret = stat(binarye->binary.file, &s);
339 memset(cwd, 0, sizeof(cwd));
340 if (!getcwd(cwd, sizeof(cwd))) {
341 dir = "current working directory";
342 perror("getcwd() failed");
346 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
347 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
348 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
349 binarye->binary.file, dir);
353 headersz += sizeof(struct opt_hdr_v1) +
355 (binarye->binary.nargs + 2) * sizeof(uint32_t);
360 #if defined(CONFIG_SYS_U_BOOT_OFFS)
361 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
362 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
363 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
364 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
365 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
368 headersz = CONFIG_SYS_U_BOOT_OFFS;
373 * The payload should be aligned on some reasonable
376 return ALIGN_SUP(headersz, 4096);
379 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
382 struct image_cfg_element *e, *binarye;
383 struct main_hdr_v1 *main_hdr;
390 * Calculate the size of the header and the size of the
393 headersz = image_headersz_v1(params, &hasext);
397 image = malloc(headersz);
399 fprintf(stderr, "Cannot allocate memory for image\n");
403 memset(image, 0, headersz);
405 cur = main_hdr = image;
406 cur += sizeof(struct main_hdr_v1);
408 /* Fill the main header */
409 main_hdr->blocksize =
410 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
411 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
412 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
413 main_hdr->destaddr = cpu_to_le32(params->addr)
414 - sizeof(image_header_t);
415 main_hdr->execaddr = cpu_to_le32(params->ep);
416 main_hdr->srcaddr = cpu_to_le32(headersz);
417 main_hdr->ext = hasext;
418 main_hdr->version = 1;
419 e = image_find_option(IMAGE_CFG_BOOT_FROM);
421 main_hdr->blockid = e->bootfrom;
422 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
424 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
425 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
427 main_hdr->nandbadblklocation = e->nandbadblklocation;
428 e = image_find_option(IMAGE_CFG_BAUDRATE);
430 main_hdr->options = baudrate_to_option(e->baudrate);
431 e = image_find_option(IMAGE_CFG_DEBUG);
433 main_hdr->flags = e->debug ? 0x1 : 0;
435 binarye = image_find_option(IMAGE_CFG_BINARY);
437 struct opt_hdr_v1 *hdr = cur;
444 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
446 bin = fopen(binarye->binary.file, "r");
448 fprintf(stderr, "Cannot open binary file %s\n",
449 binarye->binary.file);
453 fstat(fileno(bin), &s);
455 binhdrsz = sizeof(struct opt_hdr_v1) +
456 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
460 * The size includes the binary image size, rounded
461 * up to a 4-byte boundary. Plus 4 bytes for the
462 * next-header byte and 3-byte alignment at the end.
464 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
465 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
466 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
468 cur += sizeof(struct opt_hdr_v1);
471 *args = cpu_to_le32(binarye->binary.nargs);
473 for (argi = 0; argi < binarye->binary.nargs; argi++)
474 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
476 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
478 ret = fread(cur, s.st_size, 1, bin);
481 "Could not read binary image %s\n",
482 binarye->binary.file);
488 cur += ALIGN_SUP(s.st_size, 4);
491 * For now, we don't support more than one binary
492 * header, and no other header types are
493 * supported. So, the binary header is necessarily the
496 *((uint32_t *)cur) = 0x00000000;
498 cur += sizeof(uint32_t);
501 /* Calculate and set the header checksum */
502 main_hdr->checksum = image_checksum8(main_hdr, headersz);
508 static int image_create_config_parse_oneline(char *line,
509 struct image_cfg_element *el)
511 char *keyword, *saveptr;
512 char deliminiters[] = " \t";
514 keyword = strtok_r(line, deliminiters, &saveptr);
515 if (!strcmp(keyword, "VERSION")) {
516 char *value = strtok_r(NULL, deliminiters, &saveptr);
517 el->type = IMAGE_CFG_VERSION;
518 el->version = atoi(value);
519 } else if (!strcmp(keyword, "BOOT_FROM")) {
520 char *value = strtok_r(NULL, deliminiters, &saveptr);
521 int ret = image_boot_mode_id(value);
524 "Invalid boot media '%s'\n", value);
527 el->type = IMAGE_CFG_BOOT_FROM;
529 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
530 char *value = strtok_r(NULL, deliminiters, &saveptr);
531 el->type = IMAGE_CFG_NAND_BLKSZ;
532 el->nandblksz = strtoul(value, NULL, 16);
533 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
534 char *value = strtok_r(NULL, deliminiters, &saveptr);
535 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
536 el->nandbadblklocation =
537 strtoul(value, NULL, 16);
538 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
539 char *value = strtok_r(NULL, deliminiters, &saveptr);
540 int ret = image_nand_ecc_mode_id(value);
543 "Invalid NAND ECC mode '%s'\n", value);
546 el->type = IMAGE_CFG_NAND_ECC_MODE;
547 el->nandeccmode = ret;
548 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
549 char *value = strtok_r(NULL, deliminiters, &saveptr);
550 el->type = IMAGE_CFG_NAND_PAGESZ;
551 el->nandpagesz = strtoul(value, NULL, 16);
552 } else if (!strcmp(keyword, "BINARY")) {
553 char *value = strtok_r(NULL, deliminiters, &saveptr);
556 el->type = IMAGE_CFG_BINARY;
557 el->binary.file = strdup(value);
559 value = strtok_r(NULL, deliminiters, &saveptr);
562 el->binary.args[argi] = strtoul(value, NULL, 16);
564 if (argi >= BINARY_MAX_ARGS) {
566 "Too many argument for binary\n");
570 el->binary.nargs = argi;
571 } else if (!strcmp(keyword, "DATA")) {
572 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
573 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
575 if (!value1 || !value2) {
577 "Invalid number of arguments for DATA\n");
581 el->type = IMAGE_CFG_DATA;
582 el->regdata.raddr = strtoul(value1, NULL, 16);
583 el->regdata.rdata = strtoul(value2, NULL, 16);
584 } else if (!strcmp(keyword, "BAUDRATE")) {
585 char *value = strtok_r(NULL, deliminiters, &saveptr);
586 el->type = IMAGE_CFG_BAUDRATE;
587 el->baudrate = strtoul(value, NULL, 10);
588 } else if (!strcmp(keyword, "DEBUG")) {
589 char *value = strtok_r(NULL, deliminiters, &saveptr);
590 el->type = IMAGE_CFG_DEBUG;
591 el->debug = strtoul(value, NULL, 10);
593 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
600 * Parse the configuration file 'fcfg' into the array of configuration
601 * elements 'image_cfg', and return the number of configuration
602 * elements in 'cfgn'.
604 static int image_create_config_parse(FILE *fcfg)
609 /* Parse the configuration file */
610 while (!feof(fcfg)) {
614 /* Read the current line */
615 memset(buf, 0, sizeof(buf));
616 line = fgets(buf, sizeof(buf), fcfg);
620 /* Ignore useless lines */
621 if (line[0] == '\n' || line[0] == '#')
624 /* Strip final newline */
625 if (line[strlen(line) - 1] == '\n')
626 line[strlen(line) - 1] = 0;
628 /* Parse the current line */
629 ret = image_create_config_parse_oneline(line,
636 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
638 "Too many configuration elements in .cfg file\n");
647 static int image_get_version(void)
649 struct image_cfg_element *e;
651 e = image_find_option(IMAGE_CFG_VERSION);
658 static int image_version_file(const char *input)
664 fcfg = fopen(input, "r");
666 fprintf(stderr, "Could not open input file %s\n", input);
670 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
671 sizeof(struct image_cfg_element));
673 fprintf(stderr, "Cannot allocate memory\n");
679 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
682 ret = image_create_config_parse(fcfg);
689 version = image_get_version();
690 /* Fallback to version 0 is no version is provided in the cfg file */
699 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
700 struct image_tool_params *params)
710 fcfg = fopen(params->imagename, "r");
712 fprintf(stderr, "Could not open input file %s\n",
717 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
718 sizeof(struct image_cfg_element));
720 fprintf(stderr, "Cannot allocate memory\n");
726 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
729 ret = image_create_config_parse(fcfg);
736 /* The MVEBU BootROM does not allow non word aligned payloads */
737 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
739 version = image_get_version();
742 * Fallback to version 0 if no version is provided in the
747 image = image_create_v0(&headersz, params, sbuf->st_size);
751 image = image_create_v1(&headersz, params, sbuf->st_size);
755 fprintf(stderr, "Unsupported version %d\n", version);
761 fprintf(stderr, "Could not create image\n");
768 /* Build and add image checksum header */
770 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
771 size = write(ifd, &checksum, sizeof(uint32_t));
772 if (size != sizeof(uint32_t)) {
773 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
774 params->cmdname, size, params->imagefile);
778 sbuf->st_size += sizeof(uint32_t);
780 /* Finally copy the header into the image area */
781 memcpy(ptr, image, headersz);
786 static void kwbimage_print_header(const void *ptr)
788 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
790 printf("Image Type: MVEBU Boot from %s Image\n",
791 image_boot_mode_name(mhdr->blockid));
792 printf("Image version:%d\n", image_version((void *)ptr));
793 printf("Data Size: ");
794 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
795 printf("Load Address: %08x\n", mhdr->destaddr);
796 printf("Entry Point: %08x\n", mhdr->execaddr);
799 static int kwbimage_check_image_types(uint8_t type)
801 if (type == IH_TYPE_KWBIMAGE)
807 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
808 struct image_tool_params *params)
810 struct main_hdr_v0 *main_hdr;
811 struct ext_hdr_v0 *ext_hdr;
814 main_hdr = (void *)ptr;
815 checksum = image_checksum8(ptr,
816 sizeof(struct main_hdr_v0)
818 if (checksum != main_hdr->checksum)
819 return -FDT_ERR_BADSTRUCTURE;
821 /* Only version 0 extended header has checksum */
822 if (image_version((void *)ptr) == 0) {
823 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
824 checksum = image_checksum8(ext_hdr,
825 sizeof(struct ext_hdr_v0)
827 if (checksum != ext_hdr->checksum)
828 return -FDT_ERR_BADSTRUCTURE;
834 static int kwbimage_generate(struct image_tool_params *params,
835 struct image_type_params *tparams)
841 version = image_version_file(params->imagename);
843 alloc_len = sizeof(struct main_hdr_v0) +
844 sizeof(struct ext_hdr_v0);
846 alloc_len = image_headersz_v1(params, NULL);
849 hdr = malloc(alloc_len);
851 fprintf(stderr, "%s: malloc return failure: %s\n",
852 params->cmdname, strerror(errno));
856 memset(hdr, 0, alloc_len);
857 tparams->header_size = alloc_len;
861 * The resulting image needs to be 4-byte aligned. At least
862 * the Marvell hdrparser tool complains if its unaligned.
863 * By returning 1 here in this function, called via
864 * tparams->vrec_header() in mkimage.c, mkimage will
865 * automatically pad the the resulting image to a 4-byte
872 * Report Error if xflag is set in addition to default
874 static int kwbimage_check_params(struct image_tool_params *params)
876 if (!strlen(params->imagename)) {
877 fprintf(stderr, "Error:%s - Configuration file not specified, "
878 "it is needed for kwbimage generation\n",
883 return (params->dflag && (params->fflag || params->lflag)) ||
884 (params->fflag && (params->dflag || params->lflag)) ||
885 (params->lflag && (params->dflag || params->fflag)) ||
886 (params->xflag) || !(strlen(params->imagename));
890 * kwbimage type parameters definition
894 "Marvell MVEBU Boot Image support",
897 kwbimage_check_params,
898 kwbimage_verify_header,
899 kwbimage_print_header,
902 kwbimage_check_image_types,