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");
373 headersz
= CONFIG_SYS_U_BOOT_OFFS
;
377 * The payload should be aligned on some reasonable
380 return ALIGN_SUP(headersz
, 4096);
383 int add_binary_header_v1(uint8_t *cur
)
385 struct image_cfg_element
*binarye
;
386 struct opt_hdr_v1
*hdr
= (struct opt_hdr_v1
*)cur
;
394 binarye
= image_find_option(IMAGE_CFG_BINARY
);
399 hdr
->headertype
= OPT_HDR_V1_BINARY_TYPE
;
401 bin
= fopen(binarye
->binary
.file
, "r");
403 fprintf(stderr
, "Cannot open binary file %s\n",
404 binarye
->binary
.file
);
408 fstat(fileno(bin
), &s
);
410 binhdrsz
= sizeof(struct opt_hdr_v1
) +
411 (binarye
->binary
.nargs
+ 2) * sizeof(uint32_t) +
415 * The size includes the binary image size, rounded
416 * up to a 4-byte boundary. Plus 4 bytes for the
417 * next-header byte and 3-byte alignment at the end.
419 binhdrsz
= ALIGN_SUP(binhdrsz
, 4) + 4;
420 hdr
->headersz_lsb
= cpu_to_le16(binhdrsz
& 0xFFFF);
421 hdr
->headersz_msb
= (binhdrsz
& 0xFFFF0000) >> 16;
423 cur
+= sizeof(struct opt_hdr_v1
);
425 args
= (uint32_t *)cur
;
426 *args
= cpu_to_le32(binarye
->binary
.nargs
);
428 for (argi
= 0; argi
< binarye
->binary
.nargs
; argi
++)
429 args
[argi
] = cpu_to_le32(binarye
->binary
.args
[argi
]);
431 cur
+= (binarye
->binary
.nargs
+ 1) * sizeof(uint32_t);
433 ret
= fread(cur
, s
.st_size
, 1, bin
);
436 "Could not read binary image %s\n",
437 binarye
->binary
.file
);
443 cur
+= ALIGN_SUP(s
.st_size
, 4);
446 * For now, we don't support more than one binary
447 * header, and no other header types are
448 * supported. So, the binary header is necessarily the
451 *((uint32_t *)cur
) = 0x00000000;
453 cur
+= sizeof(uint32_t);
458 static void *image_create_v1(size_t *imagesz
, struct image_tool_params
*params
,
461 struct image_cfg_element
*e
;
462 struct main_hdr_v1
*main_hdr
;
464 uint8_t *image
, *cur
;
468 * Calculate the size of the header and the size of the
471 headersz
= image_headersz_v1(&hasext
);
475 image
= malloc(headersz
);
477 fprintf(stderr
, "Cannot allocate memory for image\n");
481 memset(image
, 0, headersz
);
483 main_hdr
= (struct main_hdr_v1
*)image
;
484 cur
= image
+ sizeof(struct main_hdr_v1
);
486 /* Fill the main header */
487 main_hdr
->blocksize
=
488 cpu_to_le32(payloadsz
- headersz
+ sizeof(uint32_t));
489 main_hdr
->headersz_lsb
= cpu_to_le16(headersz
& 0xFFFF);
490 main_hdr
->headersz_msb
= (headersz
& 0xFFFF0000) >> 16;
491 main_hdr
->destaddr
= cpu_to_le32(params
->addr
)
492 - sizeof(image_header_t
);
493 main_hdr
->execaddr
= cpu_to_le32(params
->ep
);
494 main_hdr
->srcaddr
= cpu_to_le32(headersz
);
495 main_hdr
->ext
= hasext
;
496 main_hdr
->version
= 1;
497 e
= image_find_option(IMAGE_CFG_BOOT_FROM
);
499 main_hdr
->blockid
= e
->bootfrom
;
500 e
= image_find_option(IMAGE_CFG_NAND_BLKSZ
);
502 main_hdr
->nandblocksize
= e
->nandblksz
/ (64 * 1024);
503 e
= image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION
);
505 main_hdr
->nandbadblklocation
= e
->nandbadblklocation
;
506 e
= image_find_option(IMAGE_CFG_BAUDRATE
);
508 main_hdr
->options
= baudrate_to_option(e
->baudrate
);
509 e
= image_find_option(IMAGE_CFG_DEBUG
);
511 main_hdr
->flags
= e
->debug
? 0x1 : 0;
513 if (add_binary_header_v1(cur
))
516 /* Calculate and set the header checksum */
517 main_hdr
->checksum
= image_checksum8(main_hdr
, headersz
);
523 static int image_create_config_parse_oneline(char *line
,
524 struct image_cfg_element
*el
)
526 char *keyword
, *saveptr
;
527 char deliminiters
[] = " \t";
529 keyword
= strtok_r(line
, deliminiters
, &saveptr
);
530 if (!strcmp(keyword
, "VERSION")) {
531 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
533 el
->type
= IMAGE_CFG_VERSION
;
534 el
->version
= atoi(value
);
535 } else if (!strcmp(keyword
, "BOOT_FROM")) {
536 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
537 int ret
= image_boot_mode_id(value
);
541 "Invalid boot media '%s'\n", value
);
544 el
->type
= IMAGE_CFG_BOOT_FROM
;
546 } else if (!strcmp(keyword
, "NAND_BLKSZ")) {
547 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
549 el
->type
= IMAGE_CFG_NAND_BLKSZ
;
550 el
->nandblksz
= strtoul(value
, NULL
, 16);
551 } else if (!strcmp(keyword
, "NAND_BADBLK_LOCATION")) {
552 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
554 el
->type
= IMAGE_CFG_NAND_BADBLK_LOCATION
;
555 el
->nandbadblklocation
=
556 strtoul(value
, NULL
, 16);
557 } else if (!strcmp(keyword
, "NAND_ECC_MODE")) {
558 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
559 int ret
= image_nand_ecc_mode_id(value
);
563 "Invalid NAND ECC mode '%s'\n", value
);
566 el
->type
= IMAGE_CFG_NAND_ECC_MODE
;
567 el
->nandeccmode
= ret
;
568 } else if (!strcmp(keyword
, "NAND_PAGE_SIZE")) {
569 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
571 el
->type
= IMAGE_CFG_NAND_PAGESZ
;
572 el
->nandpagesz
= strtoul(value
, NULL
, 16);
573 } else if (!strcmp(keyword
, "BINARY")) {
574 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
577 el
->type
= IMAGE_CFG_BINARY
;
578 el
->binary
.file
= strdup(value
);
580 value
= strtok_r(NULL
, deliminiters
, &saveptr
);
583 el
->binary
.args
[argi
] = strtoul(value
, NULL
, 16);
585 if (argi
>= BINARY_MAX_ARGS
) {
587 "Too many argument for binary\n");
591 el
->binary
.nargs
= argi
;
592 } else if (!strcmp(keyword
, "DATA")) {
593 char *value1
= strtok_r(NULL
, deliminiters
, &saveptr
);
594 char *value2
= strtok_r(NULL
, deliminiters
, &saveptr
);
596 if (!value1
|| !value2
) {
598 "Invalid number of arguments for DATA\n");
602 el
->type
= IMAGE_CFG_DATA
;
603 el
->regdata
.raddr
= strtoul(value1
, NULL
, 16);
604 el
->regdata
.rdata
= strtoul(value2
, NULL
, 16);
605 } else if (!strcmp(keyword
, "BAUDRATE")) {
606 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
607 el
->type
= IMAGE_CFG_BAUDRATE
;
608 el
->baudrate
= strtoul(value
, NULL
, 10);
609 } else if (!strcmp(keyword
, "DEBUG")) {
610 char *value
= strtok_r(NULL
, deliminiters
, &saveptr
);
611 el
->type
= IMAGE_CFG_DEBUG
;
612 el
->debug
= strtoul(value
, NULL
, 10);
614 fprintf(stderr
, "Ignoring unknown line '%s'\n", line
);
621 * Parse the configuration file 'fcfg' into the array of configuration
622 * elements 'image_cfg', and return the number of configuration
623 * elements in 'cfgn'.
625 static int image_create_config_parse(FILE *fcfg
)
630 /* Parse the configuration file */
631 while (!feof(fcfg
)) {
635 /* Read the current line */
636 memset(buf
, 0, sizeof(buf
));
637 line
= fgets(buf
, sizeof(buf
), fcfg
);
641 /* Ignore useless lines */
642 if (line
[0] == '\n' || line
[0] == '#')
645 /* Strip final newline */
646 if (line
[strlen(line
) - 1] == '\n')
647 line
[strlen(line
) - 1] = 0;
649 /* Parse the current line */
650 ret
= image_create_config_parse_oneline(line
,
657 if (cfgi
>= IMAGE_CFG_ELEMENT_MAX
) {
659 "Too many configuration elements in .cfg file\n");
668 static int image_get_version(void)
670 struct image_cfg_element
*e
;
672 e
= image_find_option(IMAGE_CFG_VERSION
);
679 static int image_version_file(const char *input
)
685 fcfg
= fopen(input
, "r");
687 fprintf(stderr
, "Could not open input file %s\n", input
);
691 image_cfg
= malloc(IMAGE_CFG_ELEMENT_MAX
*
692 sizeof(struct image_cfg_element
));
694 fprintf(stderr
, "Cannot allocate memory\n");
700 IMAGE_CFG_ELEMENT_MAX
* sizeof(struct image_cfg_element
));
703 ret
= image_create_config_parse(fcfg
);
710 version
= image_get_version();
711 /* Fallback to version 0 is no version is provided in the cfg file */
720 static void kwbimage_set_header(void *ptr
, struct stat
*sbuf
, int ifd
,
721 struct image_tool_params
*params
)
731 fcfg
= fopen(params
->imagename
, "r");
733 fprintf(stderr
, "Could not open input file %s\n",
738 image_cfg
= malloc(IMAGE_CFG_ELEMENT_MAX
*
739 sizeof(struct image_cfg_element
));
741 fprintf(stderr
, "Cannot allocate memory\n");
747 IMAGE_CFG_ELEMENT_MAX
* sizeof(struct image_cfg_element
));
750 ret
= image_create_config_parse(fcfg
);
757 /* The MVEBU BootROM does not allow non word aligned payloads */
758 sbuf
->st_size
= ALIGN_SUP(sbuf
->st_size
, 4);
760 version
= image_get_version();
763 * Fallback to version 0 if no version is provided in the
768 image
= image_create_v0(&headersz
, params
, sbuf
->st_size
);
772 image
= image_create_v1(&headersz
, params
, sbuf
->st_size
);
776 fprintf(stderr
, "Unsupported version %d\n", version
);
782 fprintf(stderr
, "Could not create image\n");
789 /* Build and add image checksum header */
791 cpu_to_le32(image_checksum32((uint32_t *)ptr
, sbuf
->st_size
));
792 size
= write(ifd
, &checksum
, sizeof(uint32_t));
793 if (size
!= sizeof(uint32_t)) {
794 fprintf(stderr
, "Error:%s - Checksum write %d bytes %s\n",
795 params
->cmdname
, size
, params
->imagefile
);
799 sbuf
->st_size
+= sizeof(uint32_t);
801 /* Finally copy the header into the image area */
802 memcpy(ptr
, image
, headersz
);
807 static void kwbimage_print_header(const void *ptr
)
809 struct main_hdr_v0
*mhdr
= (struct main_hdr_v0
*)ptr
;
811 printf("Image Type: MVEBU Boot from %s Image\n",
812 image_boot_mode_name(mhdr
->blockid
));
813 printf("Image version:%d\n", image_version((void *)ptr
));
814 printf("Data Size: ");
815 genimg_print_size(mhdr
->blocksize
- sizeof(uint32_t));
816 printf("Load Address: %08x\n", mhdr
->destaddr
);
817 printf("Entry Point: %08x\n", mhdr
->execaddr
);
820 static int kwbimage_check_image_types(uint8_t type
)
822 if (type
== IH_TYPE_KWBIMAGE
)
828 static int kwbimage_verify_header(unsigned char *ptr
, int image_size
,
829 struct image_tool_params
*params
)
831 struct main_hdr_v0
*main_hdr
;
834 main_hdr
= (struct main_hdr_v0
*)ptr
;
835 checksum
= image_checksum8(ptr
,
836 sizeof(struct main_hdr_v0
)
838 if (checksum
!= main_hdr
->checksum
)
839 return -FDT_ERR_BADSTRUCTURE
;
841 /* Only version 0 extended header has checksum */
842 if (image_version((void *)ptr
) == 0) {
843 struct ext_hdr_v0
*ext_hdr
;
845 ext_hdr
= (struct ext_hdr_v0
*)
846 (ptr
+ sizeof(struct main_hdr_v0
));
847 checksum
= image_checksum8(ext_hdr
,
848 sizeof(struct ext_hdr_v0
)
850 if (checksum
!= ext_hdr
->checksum
)
851 return -FDT_ERR_BADSTRUCTURE
;
857 static int kwbimage_generate(struct image_tool_params
*params
,
858 struct image_type_params
*tparams
)
864 version
= image_version_file(params
->imagename
);
866 alloc_len
= sizeof(struct main_hdr_v0
) +
867 sizeof(struct ext_hdr_v0
);
869 alloc_len
= image_headersz_v1(NULL
);
872 hdr
= malloc(alloc_len
);
874 fprintf(stderr
, "%s: malloc return failure: %s\n",
875 params
->cmdname
, strerror(errno
));
879 memset(hdr
, 0, alloc_len
);
880 tparams
->header_size
= alloc_len
;
884 * The resulting image needs to be 4-byte aligned. At least
885 * the Marvell hdrparser tool complains if its unaligned.
886 * By returning 1 here in this function, called via
887 * tparams->vrec_header() in mkimage.c, mkimage will
888 * automatically pad the the resulting image to a 4-byte
895 * Report Error if xflag is set in addition to default
897 static int kwbimage_check_params(struct image_tool_params
*params
)
899 if (!strlen(params
->imagename
)) {
900 char *msg
= "Configuration file for kwbimage creation omitted";
902 fprintf(stderr
, "Error:%s - %s\n", params
->cmdname
, msg
);
906 return (params
->dflag
&& (params
->fflag
|| params
->lflag
)) ||
907 (params
->fflag
&& (params
->dflag
|| params
->lflag
)) ||
908 (params
->lflag
&& (params
->dflag
|| params
->fflag
)) ||
909 (params
->xflag
) || !(strlen(params
->imagename
));
913 * kwbimage type parameters definition
917 "Marvell MVEBU Boot Image support",
920 kwbimage_check_params
,
921 kwbimage_verify_header
,
922 kwbimage_print_header
,
925 kwbimage_check_image_types
,