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;
237 * Calculate the size of the header and the size of the
240 headersz = sizeof(struct main_hdr_v0);
242 if (image_count_options(IMAGE_CFG_DATA) > 0) {
244 headersz += sizeof(struct ext_hdr_v0);
247 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
248 fprintf(stderr, "More than one payload, not possible\n");
252 image = malloc(headersz);
254 fprintf(stderr, "Cannot allocate memory for image\n");
258 memset(image, 0, headersz);
260 main_hdr = (struct main_hdr_v0 *)image;
262 /* Fill in the main header */
263 main_hdr->blocksize =
264 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
265 main_hdr->srcaddr = cpu_to_le32(headersz);
266 main_hdr->ext = has_ext;
267 main_hdr->destaddr = cpu_to_le32(params->addr);
268 main_hdr->execaddr = cpu_to_le32(params->ep);
270 e = image_find_option(IMAGE_CFG_BOOT_FROM);
272 main_hdr->blockid = e->bootfrom;
273 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
275 main_hdr->nandeccmode = e->nandeccmode;
276 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
278 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
279 main_hdr->checksum = image_checksum8(image,
280 sizeof(struct main_hdr_v0));
282 /* Generate the ext header */
284 struct ext_hdr_v0 *ext_hdr;
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(int *hasext)
313 struct image_cfg_element *binarye;
317 * Calculate the size of the header and the size of the
320 headersz = sizeof(struct main_hdr_v1);
322 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
323 fprintf(stderr, "More than one binary blob, not supported\n");
327 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
328 fprintf(stderr, "More than one payload, not possible\n");
332 binarye = image_find_option(IMAGE_CFG_BINARY);
337 ret = stat(binarye->binary.file, &s);
342 memset(cwd, 0, sizeof(cwd));
343 if (!getcwd(cwd, sizeof(cwd))) {
344 dir = "current working directory";
345 perror("getcwd() failed");
349 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
350 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
351 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
352 binarye->binary.file, dir);
356 headersz += sizeof(struct opt_hdr_v1) +
358 (binarye->binary.nargs + 2) * sizeof(uint32_t);
363 #if defined(CONFIG_SYS_U_BOOT_OFFS)
364 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
366 "Error: Image header (incl. SPL image) too big!\n");
367 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
368 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
369 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
372 headersz = CONFIG_SYS_U_BOOT_OFFS;
376 * The payload should be aligned on some reasonable
379 return ALIGN_SUP(headersz, 4096);
382 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
385 struct image_cfg_element *e, *binarye;
386 struct main_hdr_v1 *main_hdr;
388 uint8_t *image, *cur;
392 * Calculate the size of the header and the size of the
395 headersz = image_headersz_v1(&hasext);
399 image = malloc(headersz);
401 fprintf(stderr, "Cannot allocate memory for image\n");
405 memset(image, 0, headersz);
407 main_hdr = (struct main_hdr_v1 *)image;
408 cur = image + sizeof(struct main_hdr_v1);
410 /* Fill the main header */
411 main_hdr->blocksize =
412 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
413 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
414 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
415 main_hdr->destaddr = cpu_to_le32(params->addr)
416 - sizeof(image_header_t);
417 main_hdr->execaddr = cpu_to_le32(params->ep);
418 main_hdr->srcaddr = cpu_to_le32(headersz);
419 main_hdr->ext = hasext;
420 main_hdr->version = 1;
421 e = image_find_option(IMAGE_CFG_BOOT_FROM);
423 main_hdr->blockid = e->bootfrom;
424 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
426 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
427 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
429 main_hdr->nandbadblklocation = e->nandbadblklocation;
430 e = image_find_option(IMAGE_CFG_BAUDRATE);
432 main_hdr->options = baudrate_to_option(e->baudrate);
433 e = image_find_option(IMAGE_CFG_DEBUG);
435 main_hdr->flags = e->debug ? 0x1 : 0;
437 binarye = image_find_option(IMAGE_CFG_BINARY);
439 struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;
447 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
449 bin = fopen(binarye->binary.file, "r");
451 fprintf(stderr, "Cannot open binary file %s\n",
452 binarye->binary.file);
456 fstat(fileno(bin), &s);
458 binhdrsz = sizeof(struct opt_hdr_v1) +
459 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
463 * The size includes the binary image size, rounded
464 * up to a 4-byte boundary. Plus 4 bytes for the
465 * next-header byte and 3-byte alignment at the end.
467 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
468 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
469 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
471 cur += sizeof(struct opt_hdr_v1);
473 args = (uint32_t *)cur;
474 *args = cpu_to_le32(binarye->binary.nargs);
476 for (argi = 0; argi < binarye->binary.nargs; argi++)
477 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
479 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
481 ret = fread(cur, s.st_size, 1, bin);
484 "Could not read binary image %s\n",
485 binarye->binary.file);
491 cur += ALIGN_SUP(s.st_size, 4);
494 * For now, we don't support more than one binary
495 * header, and no other header types are
496 * supported. So, the binary header is necessarily the
499 *((uint32_t *)cur) = 0x00000000;
501 cur += sizeof(uint32_t);
504 /* Calculate and set the header checksum */
505 main_hdr->checksum = image_checksum8(main_hdr, headersz);
511 static int image_create_config_parse_oneline(char *line,
512 struct image_cfg_element *el)
514 char *keyword, *saveptr;
515 char deliminiters[] = " \t";
517 keyword = strtok_r(line, deliminiters, &saveptr);
518 if (!strcmp(keyword, "VERSION")) {
519 char *value = strtok_r(NULL, deliminiters, &saveptr);
521 el->type = IMAGE_CFG_VERSION;
522 el->version = atoi(value);
523 } else if (!strcmp(keyword, "BOOT_FROM")) {
524 char *value = strtok_r(NULL, deliminiters, &saveptr);
525 int ret = image_boot_mode_id(value);
529 "Invalid boot media '%s'\n", value);
532 el->type = IMAGE_CFG_BOOT_FROM;
534 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
535 char *value = strtok_r(NULL, deliminiters, &saveptr);
537 el->type = IMAGE_CFG_NAND_BLKSZ;
538 el->nandblksz = strtoul(value, NULL, 16);
539 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
540 char *value = strtok_r(NULL, deliminiters, &saveptr);
542 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
543 el->nandbadblklocation =
544 strtoul(value, NULL, 16);
545 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
546 char *value = strtok_r(NULL, deliminiters, &saveptr);
547 int ret = image_nand_ecc_mode_id(value);
551 "Invalid NAND ECC mode '%s'\n", value);
554 el->type = IMAGE_CFG_NAND_ECC_MODE;
555 el->nandeccmode = ret;
556 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
557 char *value = strtok_r(NULL, deliminiters, &saveptr);
559 el->type = IMAGE_CFG_NAND_PAGESZ;
560 el->nandpagesz = strtoul(value, NULL, 16);
561 } else if (!strcmp(keyword, "BINARY")) {
562 char *value = strtok_r(NULL, deliminiters, &saveptr);
565 el->type = IMAGE_CFG_BINARY;
566 el->binary.file = strdup(value);
568 value = strtok_r(NULL, deliminiters, &saveptr);
571 el->binary.args[argi] = strtoul(value, NULL, 16);
573 if (argi >= BINARY_MAX_ARGS) {
575 "Too many argument for binary\n");
579 el->binary.nargs = argi;
580 } else if (!strcmp(keyword, "DATA")) {
581 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
582 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
584 if (!value1 || !value2) {
586 "Invalid number of arguments for DATA\n");
590 el->type = IMAGE_CFG_DATA;
591 el->regdata.raddr = strtoul(value1, NULL, 16);
592 el->regdata.rdata = strtoul(value2, NULL, 16);
593 } else if (!strcmp(keyword, "BAUDRATE")) {
594 char *value = strtok_r(NULL, deliminiters, &saveptr);
595 el->type = IMAGE_CFG_BAUDRATE;
596 el->baudrate = strtoul(value, NULL, 10);
597 } else if (!strcmp(keyword, "DEBUG")) {
598 char *value = strtok_r(NULL, deliminiters, &saveptr);
599 el->type = IMAGE_CFG_DEBUG;
600 el->debug = strtoul(value, NULL, 10);
602 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
609 * Parse the configuration file 'fcfg' into the array of configuration
610 * elements 'image_cfg', and return the number of configuration
611 * elements in 'cfgn'.
613 static int image_create_config_parse(FILE *fcfg)
618 /* Parse the configuration file */
619 while (!feof(fcfg)) {
623 /* Read the current line */
624 memset(buf, 0, sizeof(buf));
625 line = fgets(buf, sizeof(buf), fcfg);
629 /* Ignore useless lines */
630 if (line[0] == '\n' || line[0] == '#')
633 /* Strip final newline */
634 if (line[strlen(line) - 1] == '\n')
635 line[strlen(line) - 1] = 0;
637 /* Parse the current line */
638 ret = image_create_config_parse_oneline(line,
645 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
647 "Too many configuration elements in .cfg file\n");
656 static int image_get_version(void)
658 struct image_cfg_element *e;
660 e = image_find_option(IMAGE_CFG_VERSION);
667 static int image_version_file(const char *input)
673 fcfg = fopen(input, "r");
675 fprintf(stderr, "Could not open input file %s\n", input);
679 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
680 sizeof(struct image_cfg_element));
682 fprintf(stderr, "Cannot allocate memory\n");
688 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
691 ret = image_create_config_parse(fcfg);
698 version = image_get_version();
699 /* Fallback to version 0 is no version is provided in the cfg file */
708 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
709 struct image_tool_params *params)
719 fcfg = fopen(params->imagename, "r");
721 fprintf(stderr, "Could not open input file %s\n",
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 /* The MVEBU BootROM does not allow non word aligned payloads */
746 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
748 version = image_get_version();
751 * Fallback to version 0 if no version is provided in the
756 image = image_create_v0(&headersz, params, sbuf->st_size);
760 image = image_create_v1(&headersz, params, sbuf->st_size);
764 fprintf(stderr, "Unsupported version %d\n", version);
770 fprintf(stderr, "Could not create image\n");
777 /* Build and add image checksum header */
779 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
780 size = write(ifd, &checksum, sizeof(uint32_t));
781 if (size != sizeof(uint32_t)) {
782 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
783 params->cmdname, size, params->imagefile);
787 sbuf->st_size += sizeof(uint32_t);
789 /* Finally copy the header into the image area */
790 memcpy(ptr, image, headersz);
795 static void kwbimage_print_header(const void *ptr)
797 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
799 printf("Image Type: MVEBU Boot from %s Image\n",
800 image_boot_mode_name(mhdr->blockid));
801 printf("Image version:%d\n", image_version((void *)ptr));
802 printf("Data Size: ");
803 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
804 printf("Load Address: %08x\n", mhdr->destaddr);
805 printf("Entry Point: %08x\n", mhdr->execaddr);
808 static int kwbimage_check_image_types(uint8_t type)
810 if (type == IH_TYPE_KWBIMAGE)
816 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
817 struct image_tool_params *params)
819 struct main_hdr_v0 *main_hdr;
822 main_hdr = (struct main_hdr_v0 *)ptr;
823 checksum = image_checksum8(ptr,
824 sizeof(struct main_hdr_v0)
826 if (checksum != main_hdr->checksum)
827 return -FDT_ERR_BADSTRUCTURE;
829 /* Only version 0 extended header has checksum */
830 if (image_version((void *)ptr) == 0) {
831 struct ext_hdr_v0 *ext_hdr;
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(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,