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 */
60 IMAGE_CFG_VERSION = 0x1,
65 IMAGE_CFG_NAND_BADBLK_LOCATION,
66 IMAGE_CFG_NAND_ECC_MODE,
67 IMAGE_CFG_NAND_PAGESZ,
77 static const char * const id_strs[] = {
78 [IMAGE_CFG_VERSION] = "VERSION",
79 [IMAGE_CFG_BOOT_FROM] = "BOOT_FROM",
80 [IMAGE_CFG_DEST_ADDR] = "DEST_ADDR",
81 [IMAGE_CFG_EXEC_ADDR] = "EXEC_ADDR",
82 [IMAGE_CFG_NAND_BLKSZ] = "NAND_BLKSZ",
83 [IMAGE_CFG_NAND_BADBLK_LOCATION] = "NAND_BADBLK_LOCATION",
84 [IMAGE_CFG_NAND_ECC_MODE] = "NAND_ECC_MODE",
85 [IMAGE_CFG_NAND_PAGESZ] = "NAND_PAGE_SIZE",
86 [IMAGE_CFG_BINARY] = "BINARY",
87 [IMAGE_CFG_PAYLOAD] = "PAYLOAD",
88 [IMAGE_CFG_DATA] = "DATA",
89 [IMAGE_CFG_BAUDRATE] = "BAUDRATE",
90 [IMAGE_CFG_DEBUG] = "DEBUG",
93 struct image_cfg_element {
94 enum image_cfg_type type;
97 unsigned int bootfrom;
100 unsigned int args[BINARY_MAX_ARGS];
104 unsigned int dstaddr;
105 unsigned int execaddr;
106 unsigned int nandblksz;
107 unsigned int nandbadblklocation;
108 unsigned int nandeccmode;
109 unsigned int nandpagesz;
110 struct ext_hdr_v0_reg regdata;
111 unsigned int baudrate;
116 #define IMAGE_CFG_ELEMENT_MAX 256
119 * Utility functions to manipulate boot mode and ecc modes (convert
120 * them back and forth between description strings and the
121 * corresponding numerical identifiers).
124 static const char *image_boot_mode_name(unsigned int id)
128 for (i = 0; boot_modes[i].name; i++)
129 if (boot_modes[i].id == id)
130 return boot_modes[i].name;
134 int image_boot_mode_id(const char *boot_mode_name)
138 for (i = 0; boot_modes[i].name; i++)
139 if (!strcmp(boot_modes[i].name, boot_mode_name))
140 return boot_modes[i].id;
145 int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
149 for (i = 0; nand_ecc_modes[i].name; i++)
150 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
151 return nand_ecc_modes[i].id;
155 static struct image_cfg_element *
156 image_find_option(unsigned int optiontype)
160 for (i = 0; i < cfgn; i++) {
161 if (image_cfg[i].type == optiontype)
162 return &image_cfg[i];
169 image_count_options(unsigned int optiontype)
172 unsigned int count = 0;
174 for (i = 0; i < cfgn; i++)
175 if (image_cfg[i].type == optiontype)
182 * Compute a 8-bit checksum of a memory area. This algorithm follows
183 * the requirements of the Marvell SoC BootROM specifications.
185 static uint8_t image_checksum8(void *start, uint32_t len)
190 /* check len and return zero checksum if invalid */
202 static uint32_t image_checksum32(void *start, uint32_t len)
207 /* check len and return zero checksum if invalid */
211 if (len % sizeof(uint32_t)) {
212 fprintf(stderr, "Length %d is not in multiple of %zu\n",
213 len, sizeof(uint32_t));
220 len -= sizeof(uint32_t);
226 static uint8_t baudrate_to_option(unsigned int baudrate)
230 return MAIN_HDR_V1_OPT_BAUD_2400;
232 return MAIN_HDR_V1_OPT_BAUD_4800;
234 return MAIN_HDR_V1_OPT_BAUD_9600;
236 return MAIN_HDR_V1_OPT_BAUD_19200;
238 return MAIN_HDR_V1_OPT_BAUD_38400;
240 return MAIN_HDR_V1_OPT_BAUD_57600;
242 return MAIN_HDR_V1_OPT_BAUD_115200;
244 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
248 static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
251 struct image_cfg_element *e;
253 struct main_hdr_v0 *main_hdr;
258 * Calculate the size of the header and the size of the
261 headersz = sizeof(struct main_hdr_v0);
263 if (image_count_options(IMAGE_CFG_DATA) > 0) {
265 headersz += sizeof(struct ext_hdr_v0);
268 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
269 fprintf(stderr, "More than one payload, not possible\n");
273 image = malloc(headersz);
275 fprintf(stderr, "Cannot allocate memory for image\n");
279 memset(image, 0, headersz);
281 main_hdr = (struct main_hdr_v0 *)image;
283 /* Fill in the main header */
284 main_hdr->blocksize =
285 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
286 main_hdr->srcaddr = cpu_to_le32(headersz);
287 main_hdr->ext = has_ext;
288 main_hdr->destaddr = cpu_to_le32(params->addr);
289 main_hdr->execaddr = cpu_to_le32(params->ep);
291 e = image_find_option(IMAGE_CFG_BOOT_FROM);
293 main_hdr->blockid = e->bootfrom;
294 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
296 main_hdr->nandeccmode = e->nandeccmode;
297 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
299 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
300 main_hdr->checksum = image_checksum8(image,
301 sizeof(struct main_hdr_v0));
303 /* Generate the ext header */
305 struct ext_hdr_v0 *ext_hdr;
308 ext_hdr = (struct ext_hdr_v0 *)
309 (image + sizeof(struct main_hdr_v0));
310 ext_hdr->offset = cpu_to_le32(0x40);
312 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
313 e = &image_cfg[cfgi];
314 if (e->type != IMAGE_CFG_DATA)
317 ext_hdr->rcfg[datai].raddr =
318 cpu_to_le32(e->regdata.raddr);
319 ext_hdr->rcfg[datai].rdata =
320 cpu_to_le32(e->regdata.rdata);
324 ext_hdr->checksum = image_checksum8(ext_hdr,
325 sizeof(struct ext_hdr_v0));
332 static size_t image_headersz_v1(int *hasext)
334 struct image_cfg_element *binarye;
338 * Calculate the size of the header and the size of the
341 headersz = sizeof(struct main_hdr_v1);
343 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
344 fprintf(stderr, "More than one binary blob, not supported\n");
348 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
349 fprintf(stderr, "More than one payload, not possible\n");
353 binarye = image_find_option(IMAGE_CFG_BINARY);
358 ret = stat(binarye->binary.file, &s);
363 memset(cwd, 0, sizeof(cwd));
364 if (!getcwd(cwd, sizeof(cwd))) {
365 dir = "current working directory";
366 perror("getcwd() failed");
370 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
371 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
372 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
373 binarye->binary.file, dir);
377 headersz += sizeof(struct opt_hdr_v1) +
379 (binarye->binary.nargs + 2) * sizeof(uint32_t);
384 #if defined(CONFIG_SYS_U_BOOT_OFFS)
385 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
387 "Error: Image header (incl. SPL image) too big!\n");
388 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
389 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
390 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
394 headersz = CONFIG_SYS_U_BOOT_OFFS;
398 * The payload should be aligned on some reasonable
401 return ALIGN_SUP(headersz, 4096);
404 int add_binary_header_v1(uint8_t *cur)
406 struct image_cfg_element *binarye;
407 struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;
415 binarye = image_find_option(IMAGE_CFG_BINARY);
420 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
422 bin = fopen(binarye->binary.file, "r");
424 fprintf(stderr, "Cannot open binary file %s\n",
425 binarye->binary.file);
429 fstat(fileno(bin), &s);
431 binhdrsz = sizeof(struct opt_hdr_v1) +
432 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
436 * The size includes the binary image size, rounded
437 * up to a 4-byte boundary. Plus 4 bytes for the
438 * next-header byte and 3-byte alignment at the end.
440 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
441 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
442 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
444 cur += sizeof(struct opt_hdr_v1);
446 args = (uint32_t *)cur;
447 *args = cpu_to_le32(binarye->binary.nargs);
449 for (argi = 0; argi < binarye->binary.nargs; argi++)
450 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
452 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
454 ret = fread(cur, s.st_size, 1, bin);
457 "Could not read binary image %s\n",
458 binarye->binary.file);
464 cur += ALIGN_SUP(s.st_size, 4);
467 * For now, we don't support more than one binary
468 * header, and no other header types are
469 * supported. So, the binary header is necessarily the
472 *((uint32_t *)cur) = 0x00000000;
474 cur += sizeof(uint32_t);
479 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
482 struct image_cfg_element *e;
483 struct main_hdr_v1 *main_hdr;
485 uint8_t *image, *cur;
489 * Calculate the size of the header and the size of the
492 headersz = image_headersz_v1(&hasext);
496 image = malloc(headersz);
498 fprintf(stderr, "Cannot allocate memory for image\n");
502 memset(image, 0, headersz);
504 main_hdr = (struct main_hdr_v1 *)image;
505 cur = image + sizeof(struct main_hdr_v1);
507 /* Fill the main header */
508 main_hdr->blocksize =
509 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
510 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
511 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
512 main_hdr->destaddr = cpu_to_le32(params->addr)
513 - sizeof(image_header_t);
514 main_hdr->execaddr = cpu_to_le32(params->ep);
515 main_hdr->srcaddr = cpu_to_le32(headersz);
516 main_hdr->ext = hasext;
517 main_hdr->version = 1;
518 e = image_find_option(IMAGE_CFG_BOOT_FROM);
520 main_hdr->blockid = e->bootfrom;
521 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
523 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
524 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
526 main_hdr->nandbadblklocation = e->nandbadblklocation;
527 e = image_find_option(IMAGE_CFG_BAUDRATE);
529 main_hdr->options = baudrate_to_option(e->baudrate);
530 e = image_find_option(IMAGE_CFG_DEBUG);
532 main_hdr->flags = e->debug ? 0x1 : 0;
534 if (add_binary_header_v1(cur))
537 /* Calculate and set the header checksum */
538 main_hdr->checksum = image_checksum8(main_hdr, headersz);
544 int recognize_keyword(char *keyword)
548 for (kw_id = 1; kw_id < IMAGE_CFG_COUNT; ++kw_id)
549 if (!strcmp(keyword, id_strs[kw_id]))
555 static int image_create_config_parse_oneline(char *line,
556 struct image_cfg_element *el)
558 char *keyword, *saveptr, *value1, *value2;
559 char delimiters[] = " \t";
560 int keyword_id, ret, argi;
561 char *unknown_msg = "Ignoring unknown line '%s'\n";
563 keyword = strtok_r(line, delimiters, &saveptr);
564 keyword_id = recognize_keyword(keyword);
567 fprintf(stderr, unknown_msg, line);
571 el->type = keyword_id;
573 value1 = strtok_r(NULL, delimiters, &saveptr);
576 fprintf(stderr, "Parameter missing in line '%s'\n", line);
580 switch (keyword_id) {
581 case IMAGE_CFG_VERSION:
582 el->version = atoi(value1);
584 case IMAGE_CFG_BOOT_FROM:
585 ret = image_boot_mode_id(value1);
588 fprintf(stderr, "Invalid boot media '%s'\n", value1);
593 case IMAGE_CFG_NAND_BLKSZ:
594 el->nandblksz = strtoul(value1, NULL, 16);
596 case IMAGE_CFG_NAND_BADBLK_LOCATION:
597 el->nandbadblklocation = strtoul(value1, NULL, 16);
599 case IMAGE_CFG_NAND_ECC_MODE:
600 ret = image_nand_ecc_mode_id(value1);
603 fprintf(stderr, "Invalid NAND ECC mode '%s'\n", value1);
606 el->nandeccmode = ret;
608 case IMAGE_CFG_NAND_PAGESZ:
609 el->nandpagesz = strtoul(value1, NULL, 16);
611 case IMAGE_CFG_BINARY:
614 el->binary.file = strdup(value1);
616 char *value = strtok_r(NULL, delimiters, &saveptr);
620 el->binary.args[argi] = strtoul(value, NULL, 16);
622 if (argi >= BINARY_MAX_ARGS) {
624 "Too many arguments for BINARY\n");
628 el->binary.nargs = argi;
631 value2 = strtok_r(NULL, delimiters, &saveptr);
633 if (!value1 || !value2) {
635 "Invalid number of arguments for DATA\n");
639 el->regdata.raddr = strtoul(value1, NULL, 16);
640 el->regdata.rdata = strtoul(value2, NULL, 16);
642 case IMAGE_CFG_BAUDRATE:
643 el->baudrate = strtoul(value1, NULL, 10);
645 case IMAGE_CFG_DEBUG:
646 el->debug = strtoul(value1, NULL, 10);
649 fprintf(stderr, unknown_msg, line);
656 * Parse the configuration file 'fcfg' into the array of configuration
657 * elements 'image_cfg', and return the number of configuration
658 * elements in 'cfgn'.
660 static int image_create_config_parse(FILE *fcfg)
665 /* Parse the configuration file */
666 while (!feof(fcfg)) {
670 /* Read the current line */
671 memset(buf, 0, sizeof(buf));
672 line = fgets(buf, sizeof(buf), fcfg);
676 /* Ignore useless lines */
677 if (line[0] == '\n' || line[0] == '#')
680 /* Strip final newline */
681 if (line[strlen(line) - 1] == '\n')
682 line[strlen(line) - 1] = 0;
684 /* Parse the current line */
685 ret = image_create_config_parse_oneline(line,
692 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
694 "Too many configuration elements in .cfg file\n");
703 static int image_get_version(void)
705 struct image_cfg_element *e;
707 e = image_find_option(IMAGE_CFG_VERSION);
714 static int image_version_file(const char *input)
720 fcfg = fopen(input, "r");
722 fprintf(stderr, "Could not open input file %s\n", input);
726 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
727 sizeof(struct image_cfg_element));
729 fprintf(stderr, "Cannot allocate memory\n");
735 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
738 ret = image_create_config_parse(fcfg);
745 version = image_get_version();
746 /* Fallback to version 0 is no version is provided in the cfg file */
755 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
756 struct image_tool_params *params)
766 fcfg = fopen(params->imagename, "r");
768 fprintf(stderr, "Could not open input file %s\n",
773 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
774 sizeof(struct image_cfg_element));
776 fprintf(stderr, "Cannot allocate memory\n");
782 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
785 ret = image_create_config_parse(fcfg);
792 /* The MVEBU BootROM does not allow non word aligned payloads */
793 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
795 version = image_get_version();
798 * Fallback to version 0 if no version is provided in the
803 image = image_create_v0(&headersz, params, sbuf->st_size);
807 image = image_create_v1(&headersz, params, sbuf->st_size);
811 fprintf(stderr, "Unsupported version %d\n", version);
817 fprintf(stderr, "Could not create image\n");
824 /* Build and add image checksum header */
826 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
827 size = write(ifd, &checksum, sizeof(uint32_t));
828 if (size != sizeof(uint32_t)) {
829 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
830 params->cmdname, size, params->imagefile);
834 sbuf->st_size += sizeof(uint32_t);
836 /* Finally copy the header into the image area */
837 memcpy(ptr, image, headersz);
842 static void kwbimage_print_header(const void *ptr)
844 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
846 printf("Image Type: MVEBU Boot from %s Image\n",
847 image_boot_mode_name(mhdr->blockid));
848 printf("Image version:%d\n", image_version((void *)ptr));
849 printf("Data Size: ");
850 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
851 printf("Load Address: %08x\n", mhdr->destaddr);
852 printf("Entry Point: %08x\n", mhdr->execaddr);
855 static int kwbimage_check_image_types(uint8_t type)
857 if (type == IH_TYPE_KWBIMAGE)
863 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
864 struct image_tool_params *params)
866 struct main_hdr_v0 *main_hdr;
869 main_hdr = (struct main_hdr_v0 *)ptr;
870 checksum = image_checksum8(ptr,
871 sizeof(struct main_hdr_v0)
873 if (checksum != main_hdr->checksum)
874 return -FDT_ERR_BADSTRUCTURE;
876 /* Only version 0 extended header has checksum */
877 if (image_version((void *)ptr) == 0) {
878 struct ext_hdr_v0 *ext_hdr;
880 ext_hdr = (struct ext_hdr_v0 *)
881 (ptr + sizeof(struct main_hdr_v0));
882 checksum = image_checksum8(ext_hdr,
883 sizeof(struct ext_hdr_v0)
885 if (checksum != ext_hdr->checksum)
886 return -FDT_ERR_BADSTRUCTURE;
892 static int kwbimage_generate(struct image_tool_params *params,
893 struct image_type_params *tparams)
899 version = image_version_file(params->imagename);
901 alloc_len = sizeof(struct main_hdr_v0) +
902 sizeof(struct ext_hdr_v0);
904 alloc_len = image_headersz_v1(NULL);
907 hdr = malloc(alloc_len);
909 fprintf(stderr, "%s: malloc return failure: %s\n",
910 params->cmdname, strerror(errno));
914 memset(hdr, 0, alloc_len);
915 tparams->header_size = alloc_len;
919 * The resulting image needs to be 4-byte aligned. At least
920 * the Marvell hdrparser tool complains if its unaligned.
921 * By returning 1 here in this function, called via
922 * tparams->vrec_header() in mkimage.c, mkimage will
923 * automatically pad the the resulting image to a 4-byte
930 * Report Error if xflag is set in addition to default
932 static int kwbimage_check_params(struct image_tool_params *params)
934 if (!strlen(params->imagename)) {
935 char *msg = "Configuration file for kwbimage creation omitted";
937 fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
941 return (params->dflag && (params->fflag || params->lflag)) ||
942 (params->fflag && (params->dflag || params->lflag)) ||
943 (params->lflag && (params->dflag || params->fflag)) ||
944 (params->xflag) || !(strlen(params->imagename));
948 * kwbimage type parameters definition
952 "Marvell MVEBU Boot Image support",
955 kwbimage_check_params,
956 kwbimage_verify_header,
957 kwbimage_print_header,
960 kwbimage_check_image_types,