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
);
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
= image
+ sizeof(struct main_hdr_v0
);
288 ext_hdr
->offset
= cpu_to_le32(0x40);
290 for (cfgi
= 0, datai
= 0; cfgi
< cfgn
; cfgi
++) {
291 e
= &image_cfg
[cfgi
];
292 if (e
->type
!= IMAGE_CFG_DATA
)
295 ext_hdr
->rcfg
[datai
].raddr
=
296 cpu_to_le32(e
->regdata
.raddr
);
297 ext_hdr
->rcfg
[datai
].rdata
=
298 cpu_to_le32(e
->regdata
.rdata
);
302 ext_hdr
->checksum
= image_checksum8(ext_hdr
,
303 sizeof(struct ext_hdr_v0
));
310 static size_t image_headersz_v1(struct image_tool_params
*params
,
313 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
);
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
;
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 cur
= main_hdr
= image
;
409 cur
+= 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
= 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
);
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
;
820 struct ext_hdr_v0
*ext_hdr
;
823 main_hdr
= (void *)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 ext_hdr
= (void *)ptr
+ sizeof(struct main_hdr_v0
);
833 checksum
= image_checksum8(ext_hdr
,
834 sizeof(struct ext_hdr_v0
)
836 if (checksum
!= ext_hdr
->checksum
)
837 return -FDT_ERR_BADSTRUCTURE
;
843 static int kwbimage_generate(struct image_tool_params
*params
,
844 struct image_type_params
*tparams
)
850 version
= image_version_file(params
->imagename
);
852 alloc_len
= sizeof(struct main_hdr_v0
) +
853 sizeof(struct ext_hdr_v0
);
855 alloc_len
= image_headersz_v1(params
, NULL
);
858 hdr
= malloc(alloc_len
);
860 fprintf(stderr
, "%s: malloc return failure: %s\n",
861 params
->cmdname
, strerror(errno
));
865 memset(hdr
, 0, alloc_len
);
866 tparams
->header_size
= alloc_len
;
870 * The resulting image needs to be 4-byte aligned. At least
871 * the Marvell hdrparser tool complains if its unaligned.
872 * By returning 1 here in this function, called via
873 * tparams->vrec_header() in mkimage.c, mkimage will
874 * automatically pad the the resulting image to a 4-byte
881 * Report Error if xflag is set in addition to default
883 static int kwbimage_check_params(struct image_tool_params
*params
)
885 if (!strlen(params
->imagename
)) {
886 char *msg
= "Configuration file for kwbimage creation omitted";
888 fprintf(stderr
, "Error:%s - %s\n", params
->cmdname
, msg
);
892 return (params
->dflag
&& (params
->fflag
|| params
->lflag
)) ||
893 (params
->fflag
&& (params
->dflag
|| params
->lflag
)) ||
894 (params
->lflag
&& (params
->dflag
|| params
->fflag
)) ||
895 (params
->xflag
) || !(strlen(params
->imagename
));
899 * kwbimage type parameters definition
903 "Marvell MVEBU Boot Image support",
906 kwbimage_check_params
,
907 kwbimage_verify_header
,
908 kwbimage_print_header
,
911 kwbimage_check_image_types
,