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,
75 unsigned int bootfrom;
78 unsigned int args[BINARY_MAX_ARGS];
83 unsigned int execaddr;
84 unsigned int nandblksz;
85 unsigned int nandbadblklocation;
86 unsigned int nandeccmode;
87 unsigned int nandpagesz;
88 struct ext_hdr_v0_reg regdata;
89 unsigned int baudrate;
93 #define IMAGE_CFG_ELEMENT_MAX 256
96 * Utility functions to manipulate boot mode and ecc modes (convert
97 * them back and forth between description strings and the
98 * corresponding numerical identifiers).
101 static const char *image_boot_mode_name(unsigned int id)
104 for (i = 0; boot_modes[i].name; i++)
105 if (boot_modes[i].id == id)
106 return boot_modes[i].name;
110 int image_boot_mode_id(const char *boot_mode_name)
113 for (i = 0; boot_modes[i].name; i++)
114 if (!strcmp(boot_modes[i].name, boot_mode_name))
115 return boot_modes[i].id;
120 int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
123 for (i = 0; nand_ecc_modes[i].name; i++)
124 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
125 return nand_ecc_modes[i].id;
129 static struct image_cfg_element *
130 image_find_option(unsigned int optiontype)
134 for (i = 0; i < cfgn; i++) {
135 if (image_cfg[i].type == optiontype)
136 return &image_cfg[i];
143 image_count_options(unsigned int optiontype)
146 unsigned int count = 0;
148 for (i = 0; i < cfgn; i++)
149 if (image_cfg[i].type == optiontype)
156 * Compute a 8-bit checksum of a memory area. This algorithm follows
157 * the requirements of the Marvell SoC BootROM specifications.
159 static uint8_t image_checksum8(void *start, uint32_t len)
164 /* check len and return zero checksum if invalid */
176 static uint32_t image_checksum32(void *start, uint32_t len)
181 /* check len and return zero checksum if invalid */
185 if (len % sizeof(uint32_t)) {
186 fprintf(stderr, "Length %d is not in multiple of %zu\n",
187 len, sizeof(uint32_t));
194 len -= sizeof(uint32_t);
200 static uint8_t baudrate_to_option(unsigned int baudrate)
204 return MAIN_HDR_V1_OPT_BAUD_2400;
206 return MAIN_HDR_V1_OPT_BAUD_4800;
208 return MAIN_HDR_V1_OPT_BAUD_9600;
210 return MAIN_HDR_V1_OPT_BAUD_19200;
212 return MAIN_HDR_V1_OPT_BAUD_38400;
214 return MAIN_HDR_V1_OPT_BAUD_57600;
216 return MAIN_HDR_V1_OPT_BAUD_115200;
218 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
222 static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
225 struct image_cfg_element *e;
227 struct main_hdr_v0 *main_hdr;
228 struct ext_hdr_v0 *ext_hdr;
233 * Calculate the size of the header and the size of the
236 headersz = sizeof(struct main_hdr_v0);
238 if (image_count_options(IMAGE_CFG_DATA) > 0) {
240 headersz += sizeof(struct ext_hdr_v0);
243 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
244 fprintf(stderr, "More than one payload, not possible\n");
248 image = malloc(headersz);
250 fprintf(stderr, "Cannot allocate memory for image\n");
254 memset(image, 0, headersz);
258 /* Fill in the main header */
259 main_hdr->blocksize =
260 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
261 main_hdr->srcaddr = cpu_to_le32(headersz);
262 main_hdr->ext = has_ext;
263 main_hdr->destaddr = cpu_to_le32(params->addr);
264 main_hdr->execaddr = cpu_to_le32(params->ep);
266 e = image_find_option(IMAGE_CFG_BOOT_FROM);
268 main_hdr->blockid = e->bootfrom;
269 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
271 main_hdr->nandeccmode = e->nandeccmode;
272 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
274 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
275 main_hdr->checksum = image_checksum8(image,
276 sizeof(struct main_hdr_v0));
278 /* Generate the ext header */
282 ext_hdr = image + sizeof(struct main_hdr_v0);
283 ext_hdr->offset = cpu_to_le32(0x40);
285 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
286 e = &image_cfg[cfgi];
287 if (e->type != IMAGE_CFG_DATA)
290 ext_hdr->rcfg[datai].raddr =
291 cpu_to_le32(e->regdata.raddr);
292 ext_hdr->rcfg[datai].rdata =
293 cpu_to_le32(e->regdata.rdata);
297 ext_hdr->checksum = image_checksum8(ext_hdr,
298 sizeof(struct ext_hdr_v0));
305 static size_t image_headersz_v1(struct image_tool_params *params,
308 struct image_cfg_element *binarye;
313 * Calculate the size of the header and the size of the
316 headersz = sizeof(struct main_hdr_v1);
318 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
319 fprintf(stderr, "More than one binary blob, not supported\n");
323 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
324 fprintf(stderr, "More than one payload, not possible\n");
328 binarye = image_find_option(IMAGE_CFG_BINARY);
332 ret = stat(binarye->binary.file, &s);
337 memset(cwd, 0, sizeof(cwd));
338 if (!getcwd(cwd, sizeof(cwd))) {
339 dir = "current working directory";
340 perror("getcwd() failed");
344 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
345 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
346 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
347 binarye->binary.file, dir);
351 headersz += sizeof(struct opt_hdr_v1) +
353 (binarye->binary.nargs + 2) * sizeof(uint32_t);
358 #if defined(CONFIG_SYS_U_BOOT_OFFS)
359 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
360 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
361 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
362 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
363 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
366 headersz = CONFIG_SYS_U_BOOT_OFFS;
371 * The payload should be aligned on some reasonable
374 return ALIGN_SUP(headersz, 4096);
377 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
380 struct image_cfg_element *e, *binarye;
381 struct main_hdr_v1 *main_hdr;
388 * Calculate the size of the header and the size of the
391 headersz = image_headersz_v1(params, &hasext);
395 image = malloc(headersz);
397 fprintf(stderr, "Cannot allocate memory for image\n");
401 memset(image, 0, headersz);
403 cur = main_hdr = image;
404 cur += sizeof(struct main_hdr_v1);
406 /* Fill the main header */
407 main_hdr->blocksize =
408 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
409 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
410 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
411 main_hdr->destaddr = cpu_to_le32(params->addr);
412 main_hdr->execaddr = cpu_to_le32(params->ep);
413 main_hdr->srcaddr = cpu_to_le32(headersz);
414 main_hdr->ext = hasext;
415 main_hdr->version = 1;
416 e = image_find_option(IMAGE_CFG_BOOT_FROM);
418 main_hdr->blockid = e->bootfrom;
419 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
421 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
422 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
424 main_hdr->nandbadblklocation = e->nandbadblklocation;
425 e = image_find_option(IMAGE_CFG_BAUDRATE);
427 main_hdr->options = baudrate_to_option(e->baudrate);
429 binarye = image_find_option(IMAGE_CFG_BINARY);
431 struct opt_hdr_v1 *hdr = cur;
438 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
440 bin = fopen(binarye->binary.file, "r");
442 fprintf(stderr, "Cannot open binary file %s\n",
443 binarye->binary.file);
447 fstat(fileno(bin), &s);
449 binhdrsz = sizeof(struct opt_hdr_v1) +
450 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
454 * The size includes the binary image size, rounded
455 * up to a 4-byte boundary. Plus 4 bytes for the
456 * next-header byte and 3-byte alignment at the end.
458 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
459 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
460 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
462 cur += sizeof(struct opt_hdr_v1);
465 *args = cpu_to_le32(binarye->binary.nargs);
467 for (argi = 0; argi < binarye->binary.nargs; argi++)
468 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
470 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
472 ret = fread(cur, s.st_size, 1, bin);
475 "Could not read binary image %s\n",
476 binarye->binary.file);
482 cur += ALIGN_SUP(s.st_size, 4);
485 * For now, we don't support more than one binary
486 * header, and no other header types are
487 * supported. So, the binary header is necessarily the
490 *((uint32_t *)cur) = 0x00000000;
492 cur += sizeof(uint32_t);
495 /* Calculate and set the header checksum */
496 main_hdr->checksum = image_checksum8(main_hdr, headersz);
502 static int image_create_config_parse_oneline(char *line,
503 struct image_cfg_element *el)
505 char *keyword, *saveptr;
506 char deliminiters[] = " \t";
508 keyword = strtok_r(line, deliminiters, &saveptr);
509 if (!strcmp(keyword, "VERSION")) {
510 char *value = strtok_r(NULL, deliminiters, &saveptr);
511 el->type = IMAGE_CFG_VERSION;
512 el->version = atoi(value);
513 } else if (!strcmp(keyword, "BOOT_FROM")) {
514 char *value = strtok_r(NULL, deliminiters, &saveptr);
515 int ret = image_boot_mode_id(value);
518 "Invalid boot media '%s'\n", value);
521 el->type = IMAGE_CFG_BOOT_FROM;
523 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
524 char *value = strtok_r(NULL, deliminiters, &saveptr);
525 el->type = IMAGE_CFG_NAND_BLKSZ;
526 el->nandblksz = strtoul(value, NULL, 16);
527 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
528 char *value = strtok_r(NULL, deliminiters, &saveptr);
529 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
530 el->nandbadblklocation =
531 strtoul(value, NULL, 16);
532 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
533 char *value = strtok_r(NULL, deliminiters, &saveptr);
534 int ret = image_nand_ecc_mode_id(value);
537 "Invalid NAND ECC mode '%s'\n", value);
540 el->type = IMAGE_CFG_NAND_ECC_MODE;
541 el->nandeccmode = ret;
542 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
543 char *value = strtok_r(NULL, deliminiters, &saveptr);
544 el->type = IMAGE_CFG_NAND_PAGESZ;
545 el->nandpagesz = strtoul(value, NULL, 16);
546 } else if (!strcmp(keyword, "BINARY")) {
547 char *value = strtok_r(NULL, deliminiters, &saveptr);
550 el->type = IMAGE_CFG_BINARY;
551 el->binary.file = strdup(value);
553 value = strtok_r(NULL, deliminiters, &saveptr);
556 el->binary.args[argi] = strtoul(value, NULL, 16);
558 if (argi >= BINARY_MAX_ARGS) {
560 "Too many argument for binary\n");
564 el->binary.nargs = argi;
565 } else if (!strcmp(keyword, "DATA")) {
566 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
567 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
569 if (!value1 || !value2) {
571 "Invalid number of arguments for DATA\n");
575 el->type = IMAGE_CFG_DATA;
576 el->regdata.raddr = strtoul(value1, NULL, 16);
577 el->regdata.rdata = strtoul(value2, NULL, 16);
578 } else if (!strcmp(keyword, "BAUDRATE")) {
579 char *value = strtok_r(NULL, deliminiters, &saveptr);
580 el->type = IMAGE_CFG_BAUDRATE;
581 el->baudrate = strtoul(value, NULL, 10);
583 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
590 * Parse the configuration file 'fcfg' into the array of configuration
591 * elements 'image_cfg', and return the number of configuration
592 * elements in 'cfgn'.
594 static int image_create_config_parse(FILE *fcfg)
599 /* Parse the configuration file */
600 while (!feof(fcfg)) {
604 /* Read the current line */
605 memset(buf, 0, sizeof(buf));
606 line = fgets(buf, sizeof(buf), fcfg);
610 /* Ignore useless lines */
611 if (line[0] == '\n' || line[0] == '#')
614 /* Strip final newline */
615 if (line[strlen(line) - 1] == '\n')
616 line[strlen(line) - 1] = 0;
618 /* Parse the current line */
619 ret = image_create_config_parse_oneline(line,
626 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
628 "Too many configuration elements in .cfg file\n");
637 static int image_get_version(void)
639 struct image_cfg_element *e;
641 e = image_find_option(IMAGE_CFG_VERSION);
648 static int image_version_file(const char *input)
654 fcfg = fopen(input, "r");
656 fprintf(stderr, "Could not open input file %s\n", input);
660 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
661 sizeof(struct image_cfg_element));
663 fprintf(stderr, "Cannot allocate memory\n");
669 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
672 ret = image_create_config_parse(fcfg);
679 version = image_get_version();
680 /* Fallback to version 0 is no version is provided in the cfg file */
689 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
690 struct image_tool_params *params)
700 fcfg = fopen(params->imagename, "r");
702 fprintf(stderr, "Could not open input file %s\n",
707 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
708 sizeof(struct image_cfg_element));
710 fprintf(stderr, "Cannot allocate memory\n");
716 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
719 ret = image_create_config_parse(fcfg);
726 /* The MVEBU BootROM does not allow non word aligned payloads */
727 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
729 version = image_get_version();
732 * Fallback to version 0 if no version is provided in the
737 image = image_create_v0(&headersz, params, sbuf->st_size);
741 image = image_create_v1(&headersz, params, sbuf->st_size);
745 fprintf(stderr, "Unsupported version %d\n", version);
751 fprintf(stderr, "Could not create image\n");
758 /* Build and add image checksum header */
760 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
761 size = write(ifd, &checksum, sizeof(uint32_t));
762 if (size != sizeof(uint32_t)) {
763 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
764 params->cmdname, size, params->imagefile);
768 sbuf->st_size += sizeof(uint32_t);
770 /* Finally copy the header into the image area */
771 memcpy(ptr, image, headersz);
776 static void kwbimage_print_header(const void *ptr)
778 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
780 printf("Image Type: MVEBU Boot from %s Image\n",
781 image_boot_mode_name(mhdr->blockid));
782 printf("Image version:%d\n", image_version((void *)ptr));
783 printf("Data Size: ");
784 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
785 printf("Load Address: %08x\n", mhdr->destaddr);
786 printf("Entry Point: %08x\n", mhdr->execaddr);
789 static int kwbimage_check_image_types(uint8_t type)
791 if (type == IH_TYPE_KWBIMAGE)
797 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
798 struct image_tool_params *params)
800 struct main_hdr_v0 *main_hdr;
801 struct ext_hdr_v0 *ext_hdr;
804 main_hdr = (void *)ptr;
805 checksum = image_checksum8(ptr,
806 sizeof(struct main_hdr_v0)
808 if (checksum != main_hdr->checksum)
809 return -FDT_ERR_BADSTRUCTURE;
811 /* Only version 0 extended header has checksum */
812 if (image_version((void *)ptr) == 0) {
813 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
814 checksum = image_checksum8(ext_hdr,
815 sizeof(struct ext_hdr_v0)
817 if (checksum != ext_hdr->checksum)
818 return -FDT_ERR_BADSTRUCTURE;
824 static int kwbimage_generate(struct image_tool_params *params,
825 struct image_type_params *tparams)
831 version = image_version_file(params->imagename);
833 alloc_len = sizeof(struct main_hdr_v0) +
834 sizeof(struct ext_hdr_v0);
836 alloc_len = image_headersz_v1(params, NULL);
839 hdr = malloc(alloc_len);
841 fprintf(stderr, "%s: malloc return failure: %s\n",
842 params->cmdname, strerror(errno));
846 memset(hdr, 0, alloc_len);
847 tparams->header_size = alloc_len;
851 * The resulting image needs to be 4-byte aligned. At least
852 * the Marvell hdrparser tool complains if its unaligned.
853 * By returning 1 here in this function, called via
854 * tparams->vrec_header() in mkimage.c, mkimage will
855 * automatically pad the the resulting image to a 4-byte
862 * Report Error if xflag is set in addition to default
864 static int kwbimage_check_params(struct image_tool_params *params)
866 if (!strlen(params->imagename)) {
867 fprintf(stderr, "Error:%s - Configuration file not specified, "
868 "it is needed for kwbimage generation\n",
873 return (params->dflag && (params->fflag || params->lflag)) ||
874 (params->fflag && (params->dflag || params->lflag)) ||
875 (params->lflag && (params->dflag || params->fflag)) ||
876 (params->xflag) || !(strlen(params->imagename));
880 * kwbimage type parameters definition
884 "Marvell MVEBU Boot Image support",
887 kwbimage_check_params,
888 kwbimage_verify_header,
889 kwbimage_print_header,
892 kwbimage_check_image_types,