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)
107 for (i = 0; boot_modes[i].name; i++)
108 if (boot_modes[i].id == id)
109 return boot_modes[i].name;
113 int image_boot_mode_id(const char *boot_mode_name)
117 for (i = 0; boot_modes[i].name; i++)
118 if (!strcmp(boot_modes[i].name, boot_mode_name))
119 return boot_modes[i].id;
124 int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
128 for (i = 0; nand_ecc_modes[i].name; i++)
129 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
130 return nand_ecc_modes[i].id;
134 static struct image_cfg_element *
135 image_find_option(unsigned int optiontype)
139 for (i = 0; i < cfgn; i++) {
140 if (image_cfg[i].type == optiontype)
141 return &image_cfg[i];
148 image_count_options(unsigned int optiontype)
151 unsigned int count = 0;
153 for (i = 0; i < cfgn; i++)
154 if (image_cfg[i].type == optiontype)
161 * Compute a 8-bit checksum of a memory area. This algorithm follows
162 * the requirements of the Marvell SoC BootROM specifications.
164 static uint8_t image_checksum8(void *start, uint32_t len)
169 /* check len and return zero checksum if invalid */
181 static uint32_t image_checksum32(void *start, uint32_t len)
186 /* check len and return zero checksum if invalid */
190 if (len % sizeof(uint32_t)) {
191 fprintf(stderr, "Length %d is not in multiple of %zu\n",
192 len, sizeof(uint32_t));
199 len -= sizeof(uint32_t);
205 static uint8_t baudrate_to_option(unsigned int baudrate)
209 return MAIN_HDR_V1_OPT_BAUD_2400;
211 return MAIN_HDR_V1_OPT_BAUD_4800;
213 return MAIN_HDR_V1_OPT_BAUD_9600;
215 return MAIN_HDR_V1_OPT_BAUD_19200;
217 return MAIN_HDR_V1_OPT_BAUD_38400;
219 return MAIN_HDR_V1_OPT_BAUD_57600;
221 return MAIN_HDR_V1_OPT_BAUD_115200;
223 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
227 static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
230 struct image_cfg_element *e;
232 struct main_hdr_v0 *main_hdr;
233 struct ext_hdr_v0 *ext_hdr;
238 * Calculate the size of the header and the size of the
241 headersz = sizeof(struct main_hdr_v0);
243 if (image_count_options(IMAGE_CFG_DATA) > 0) {
245 headersz += sizeof(struct ext_hdr_v0);
248 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
249 fprintf(stderr, "More than one payload, not possible\n");
253 image = malloc(headersz);
255 fprintf(stderr, "Cannot allocate memory for image\n");
259 memset(image, 0, headersz);
261 main_hdr = (struct main_hdr_v0 *)image;
263 /* Fill in the main header */
264 main_hdr->blocksize =
265 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
266 main_hdr->srcaddr = cpu_to_le32(headersz);
267 main_hdr->ext = has_ext;
268 main_hdr->destaddr = cpu_to_le32(params->addr);
269 main_hdr->execaddr = cpu_to_le32(params->ep);
271 e = image_find_option(IMAGE_CFG_BOOT_FROM);
273 main_hdr->blockid = e->bootfrom;
274 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
276 main_hdr->nandeccmode = e->nandeccmode;
277 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
279 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
280 main_hdr->checksum = image_checksum8(image,
281 sizeof(struct main_hdr_v0));
283 /* Generate the ext header */
287 ext_hdr = (struct ext_hdr_v0 *)
288 (image + sizeof(struct main_hdr_v0));
289 ext_hdr->offset = cpu_to_le32(0x40);
291 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
292 e = &image_cfg[cfgi];
293 if (e->type != IMAGE_CFG_DATA)
296 ext_hdr->rcfg[datai].raddr =
297 cpu_to_le32(e->regdata.raddr);
298 ext_hdr->rcfg[datai].rdata =
299 cpu_to_le32(e->regdata.rdata);
303 ext_hdr->checksum = image_checksum8(ext_hdr,
304 sizeof(struct ext_hdr_v0));
311 static size_t image_headersz_v1(struct image_tool_params *params,
314 struct image_cfg_element *binarye;
319 * Calculate the size of the header and the size of the
322 headersz = sizeof(struct main_hdr_v1);
324 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
325 fprintf(stderr, "More than one binary blob, not supported\n");
329 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
330 fprintf(stderr, "More than one payload, not possible\n");
334 binarye = image_find_option(IMAGE_CFG_BINARY);
338 ret = stat(binarye->binary.file, &s);
343 memset(cwd, 0, sizeof(cwd));
344 if (!getcwd(cwd, sizeof(cwd))) {
345 dir = "current working directory";
346 perror("getcwd() failed");
350 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
351 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
352 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
353 binarye->binary.file, dir);
357 headersz += sizeof(struct opt_hdr_v1) +
359 (binarye->binary.nargs + 2) * sizeof(uint32_t);
364 #if defined(CONFIG_SYS_U_BOOT_OFFS)
365 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
367 "Error: Image header (incl. SPL image) too big!\n");
368 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
369 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
370 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
373 headersz = CONFIG_SYS_U_BOOT_OFFS;
377 * The payload should be aligned on some reasonable
380 return ALIGN_SUP(headersz, 4096);
383 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
386 struct image_cfg_element *e, *binarye;
387 struct main_hdr_v1 *main_hdr;
389 uint8_t *image, *cur;
394 * Calculate the size of the header and the size of the
397 headersz = image_headersz_v1(params, &hasext);
401 image = malloc(headersz);
403 fprintf(stderr, "Cannot allocate memory for image\n");
407 memset(image, 0, headersz);
409 main_hdr = (struct main_hdr_v1 *)image;
410 cur = image + sizeof(struct main_hdr_v1);
412 /* Fill the main header */
413 main_hdr->blocksize =
414 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
415 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
416 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
417 main_hdr->destaddr = cpu_to_le32(params->addr)
418 - sizeof(image_header_t);
419 main_hdr->execaddr = cpu_to_le32(params->ep);
420 main_hdr->srcaddr = cpu_to_le32(headersz);
421 main_hdr->ext = hasext;
422 main_hdr->version = 1;
423 e = image_find_option(IMAGE_CFG_BOOT_FROM);
425 main_hdr->blockid = e->bootfrom;
426 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
428 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
429 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
431 main_hdr->nandbadblklocation = e->nandbadblklocation;
432 e = image_find_option(IMAGE_CFG_BAUDRATE);
434 main_hdr->options = baudrate_to_option(e->baudrate);
435 e = image_find_option(IMAGE_CFG_DEBUG);
437 main_hdr->flags = e->debug ? 0x1 : 0;
439 binarye = image_find_option(IMAGE_CFG_BINARY);
441 struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;
448 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
450 bin = fopen(binarye->binary.file, "r");
452 fprintf(stderr, "Cannot open binary file %s\n",
453 binarye->binary.file);
457 fstat(fileno(bin), &s);
459 binhdrsz = sizeof(struct opt_hdr_v1) +
460 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
464 * The size includes the binary image size, rounded
465 * up to a 4-byte boundary. Plus 4 bytes for the
466 * next-header byte and 3-byte alignment at the end.
468 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
469 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
470 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
472 cur += sizeof(struct opt_hdr_v1);
474 args = (uint32_t *)cur;
475 *args = cpu_to_le32(binarye->binary.nargs);
477 for (argi = 0; argi < binarye->binary.nargs; argi++)
478 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
480 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
482 ret = fread(cur, s.st_size, 1, bin);
485 "Could not read binary image %s\n",
486 binarye->binary.file);
492 cur += ALIGN_SUP(s.st_size, 4);
495 * For now, we don't support more than one binary
496 * header, and no other header types are
497 * supported. So, the binary header is necessarily the
500 *((uint32_t *)cur) = 0x00000000;
502 cur += sizeof(uint32_t);
505 /* Calculate and set the header checksum */
506 main_hdr->checksum = image_checksum8(main_hdr, headersz);
512 static int image_create_config_parse_oneline(char *line,
513 struct image_cfg_element *el)
515 char *keyword, *saveptr;
516 char deliminiters[] = " \t";
518 keyword = strtok_r(line, deliminiters, &saveptr);
519 if (!strcmp(keyword, "VERSION")) {
520 char *value = strtok_r(NULL, deliminiters, &saveptr);
522 el->type = IMAGE_CFG_VERSION;
523 el->version = atoi(value);
524 } else if (!strcmp(keyword, "BOOT_FROM")) {
525 char *value = strtok_r(NULL, deliminiters, &saveptr);
526 int ret = image_boot_mode_id(value);
530 "Invalid boot media '%s'\n", value);
533 el->type = IMAGE_CFG_BOOT_FROM;
535 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
536 char *value = strtok_r(NULL, deliminiters, &saveptr);
538 el->type = IMAGE_CFG_NAND_BLKSZ;
539 el->nandblksz = strtoul(value, NULL, 16);
540 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
541 char *value = strtok_r(NULL, deliminiters, &saveptr);
543 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
544 el->nandbadblklocation =
545 strtoul(value, NULL, 16);
546 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
547 char *value = strtok_r(NULL, deliminiters, &saveptr);
548 int ret = image_nand_ecc_mode_id(value);
552 "Invalid NAND ECC mode '%s'\n", value);
555 el->type = IMAGE_CFG_NAND_ECC_MODE;
556 el->nandeccmode = ret;
557 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
558 char *value = strtok_r(NULL, deliminiters, &saveptr);
560 el->type = IMAGE_CFG_NAND_PAGESZ;
561 el->nandpagesz = strtoul(value, NULL, 16);
562 } else if (!strcmp(keyword, "BINARY")) {
563 char *value = strtok_r(NULL, deliminiters, &saveptr);
566 el->type = IMAGE_CFG_BINARY;
567 el->binary.file = strdup(value);
569 value = strtok_r(NULL, deliminiters, &saveptr);
572 el->binary.args[argi] = strtoul(value, NULL, 16);
574 if (argi >= BINARY_MAX_ARGS) {
576 "Too many argument for binary\n");
580 el->binary.nargs = argi;
581 } else if (!strcmp(keyword, "DATA")) {
582 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
583 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
585 if (!value1 || !value2) {
587 "Invalid number of arguments for DATA\n");
591 el->type = IMAGE_CFG_DATA;
592 el->regdata.raddr = strtoul(value1, NULL, 16);
593 el->regdata.rdata = strtoul(value2, NULL, 16);
594 } else if (!strcmp(keyword, "BAUDRATE")) {
595 char *value = strtok_r(NULL, deliminiters, &saveptr);
596 el->type = IMAGE_CFG_BAUDRATE;
597 el->baudrate = strtoul(value, NULL, 10);
598 } else if (!strcmp(keyword, "DEBUG")) {
599 char *value = strtok_r(NULL, deliminiters, &saveptr);
600 el->type = IMAGE_CFG_DEBUG;
601 el->debug = strtoul(value, NULL, 10);
603 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
610 * Parse the configuration file 'fcfg' into the array of configuration
611 * elements 'image_cfg', and return the number of configuration
612 * elements in 'cfgn'.
614 static int image_create_config_parse(FILE *fcfg)
619 /* Parse the configuration file */
620 while (!feof(fcfg)) {
624 /* Read the current line */
625 memset(buf, 0, sizeof(buf));
626 line = fgets(buf, sizeof(buf), fcfg);
630 /* Ignore useless lines */
631 if (line[0] == '\n' || line[0] == '#')
634 /* Strip final newline */
635 if (line[strlen(line) - 1] == '\n')
636 line[strlen(line) - 1] = 0;
638 /* Parse the current line */
639 ret = image_create_config_parse_oneline(line,
646 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
648 "Too many configuration elements in .cfg file\n");
657 static int image_get_version(void)
659 struct image_cfg_element *e;
661 e = image_find_option(IMAGE_CFG_VERSION);
668 static int image_version_file(const char *input)
674 fcfg = fopen(input, "r");
676 fprintf(stderr, "Could not open input file %s\n", input);
680 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
681 sizeof(struct image_cfg_element));
683 fprintf(stderr, "Cannot allocate memory\n");
689 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
692 ret = image_create_config_parse(fcfg);
699 version = image_get_version();
700 /* Fallback to version 0 is no version is provided in the cfg file */
709 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
710 struct image_tool_params *params)
720 fcfg = fopen(params->imagename, "r");
722 fprintf(stderr, "Could not open input file %s\n",
727 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
728 sizeof(struct image_cfg_element));
730 fprintf(stderr, "Cannot allocate memory\n");
736 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
739 ret = image_create_config_parse(fcfg);
746 /* The MVEBU BootROM does not allow non word aligned payloads */
747 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
749 version = image_get_version();
752 * Fallback to version 0 if no version is provided in the
757 image = image_create_v0(&headersz, params, sbuf->st_size);
761 image = image_create_v1(&headersz, params, sbuf->st_size);
765 fprintf(stderr, "Unsupported version %d\n", version);
771 fprintf(stderr, "Could not create image\n");
778 /* Build and add image checksum header */
780 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
781 size = write(ifd, &checksum, sizeof(uint32_t));
782 if (size != sizeof(uint32_t)) {
783 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
784 params->cmdname, size, params->imagefile);
788 sbuf->st_size += sizeof(uint32_t);
790 /* Finally copy the header into the image area */
791 memcpy(ptr, image, headersz);
796 static void kwbimage_print_header(const void *ptr)
798 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
800 printf("Image Type: MVEBU Boot from %s Image\n",
801 image_boot_mode_name(mhdr->blockid));
802 printf("Image version:%d\n", image_version((void *)ptr));
803 printf("Data Size: ");
804 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
805 printf("Load Address: %08x\n", mhdr->destaddr);
806 printf("Entry Point: %08x\n", mhdr->execaddr);
809 static int kwbimage_check_image_types(uint8_t type)
811 if (type == IH_TYPE_KWBIMAGE)
817 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
818 struct image_tool_params *params)
820 struct main_hdr_v0 *main_hdr;
821 struct ext_hdr_v0 *ext_hdr;
824 main_hdr = (struct main_hdr_v0 *)ptr;
825 checksum = image_checksum8(ptr,
826 sizeof(struct main_hdr_v0)
828 if (checksum != main_hdr->checksum)
829 return -FDT_ERR_BADSTRUCTURE;
831 /* Only version 0 extended header has checksum */
832 if (image_version((void *)ptr) == 0) {
833 ext_hdr = (struct ext_hdr_v0 *)
834 (ptr + sizeof(struct main_hdr_v0));
835 checksum = image_checksum8(ext_hdr,
836 sizeof(struct ext_hdr_v0)
838 if (checksum != ext_hdr->checksum)
839 return -FDT_ERR_BADSTRUCTURE;
845 static int kwbimage_generate(struct image_tool_params *params,
846 struct image_type_params *tparams)
852 version = image_version_file(params->imagename);
854 alloc_len = sizeof(struct main_hdr_v0) +
855 sizeof(struct ext_hdr_v0);
857 alloc_len = image_headersz_v1(params, NULL);
860 hdr = malloc(alloc_len);
862 fprintf(stderr, "%s: malloc return failure: %s\n",
863 params->cmdname, strerror(errno));
867 memset(hdr, 0, alloc_len);
868 tparams->header_size = alloc_len;
872 * The resulting image needs to be 4-byte aligned. At least
873 * the Marvell hdrparser tool complains if its unaligned.
874 * By returning 1 here in this function, called via
875 * tparams->vrec_header() in mkimage.c, mkimage will
876 * automatically pad the the resulting image to a 4-byte
883 * Report Error if xflag is set in addition to default
885 static int kwbimage_check_params(struct image_tool_params *params)
887 if (!strlen(params->imagename)) {
888 char *msg = "Configuration file for kwbimage creation omitted";
890 fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
894 return (params->dflag && (params->fflag || params->lflag)) ||
895 (params->fflag && (params->dflag || params->lflag)) ||
896 (params->lflag && (params->dflag || params->fflag)) ||
897 (params->xflag) || !(strlen(params->imagename));
901 * kwbimage type parameters definition
905 "Marvell MVEBU Boot Image support",
908 kwbimage_check_params,
909 kwbimage_verify_header,
910 kwbimage_print_header,
913 kwbimage_check_image_types,