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(struct image_tool_params *params,
314 struct image_cfg_element *binarye;
318 * Calculate the size of the header and the size of the
321 headersz = sizeof(struct main_hdr_v1);
323 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
324 fprintf(stderr, "More than one binary blob, not supported\n");
328 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
329 fprintf(stderr, "More than one payload, not possible\n");
333 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;
393 * Calculate the size of the header and the size of the
396 headersz = image_headersz_v1(params, &hasext);
400 image = malloc(headersz);
402 fprintf(stderr, "Cannot allocate memory for image\n");
406 memset(image, 0, headersz);
408 main_hdr = (struct main_hdr_v1 *)image;
409 cur = image + sizeof(struct main_hdr_v1);
411 /* Fill the main header */
412 main_hdr->blocksize =
413 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
414 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
415 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
416 main_hdr->destaddr = cpu_to_le32(params->addr)
417 - sizeof(image_header_t);
418 main_hdr->execaddr = cpu_to_le32(params->ep);
419 main_hdr->srcaddr = cpu_to_le32(headersz);
420 main_hdr->ext = hasext;
421 main_hdr->version = 1;
422 e = image_find_option(IMAGE_CFG_BOOT_FROM);
424 main_hdr->blockid = e->bootfrom;
425 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
427 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
428 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
430 main_hdr->nandbadblklocation = e->nandbadblklocation;
431 e = image_find_option(IMAGE_CFG_BAUDRATE);
433 main_hdr->options = baudrate_to_option(e->baudrate);
434 e = image_find_option(IMAGE_CFG_DEBUG);
436 main_hdr->flags = e->debug ? 0x1 : 0;
438 binarye = image_find_option(IMAGE_CFG_BINARY);
440 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;
823 main_hdr = (struct main_hdr_v0 *)ptr;
824 checksum = image_checksum8(ptr,
825 sizeof(struct main_hdr_v0)
827 if (checksum != main_hdr->checksum)
828 return -FDT_ERR_BADSTRUCTURE;
830 /* Only version 0 extended header has checksum */
831 if (image_version((void *)ptr) == 0) {
832 struct ext_hdr_v0 *ext_hdr;
834 ext_hdr = (struct ext_hdr_v0 *)
835 (ptr + sizeof(struct main_hdr_v0));
836 checksum = image_checksum8(ext_hdr,
837 sizeof(struct ext_hdr_v0)
839 if (checksum != ext_hdr->checksum)
840 return -FDT_ERR_BADSTRUCTURE;
846 static int kwbimage_generate(struct image_tool_params *params,
847 struct image_type_params *tparams)
853 version = image_version_file(params->imagename);
855 alloc_len = sizeof(struct main_hdr_v0) +
856 sizeof(struct ext_hdr_v0);
858 alloc_len = image_headersz_v1(params, NULL);
861 hdr = malloc(alloc_len);
863 fprintf(stderr, "%s: malloc return failure: %s\n",
864 params->cmdname, strerror(errno));
868 memset(hdr, 0, alloc_len);
869 tparams->header_size = alloc_len;
873 * The resulting image needs to be 4-byte aligned. At least
874 * the Marvell hdrparser tool complains if its unaligned.
875 * By returning 1 here in this function, called via
876 * tparams->vrec_header() in mkimage.c, mkimage will
877 * automatically pad the the resulting image to a 4-byte
884 * Report Error if xflag is set in addition to default
886 static int kwbimage_check_params(struct image_tool_params *params)
888 if (!strlen(params->imagename)) {
889 char *msg = "Configuration file for kwbimage creation omitted";
891 fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
895 return (params->dflag && (params->fflag || params->lflag)) ||
896 (params->fflag && (params->dflag || params->lflag)) ||
897 (params->lflag && (params->dflag || params->fflag)) ||
898 (params->xflag) || !(strlen(params->imagename));
902 * kwbimage type parameters definition
906 "Marvell MVEBU Boot Image support",
909 kwbimage_check_params,
910 kwbimage_verify_header,
911 kwbimage_print_header,
914 kwbimage_check_image_types,