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"
19 #define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
21 /* Structure of the main header, version 0 (Kirkwood, Dove) */
23 uint8_t blockid; /*0 */
24 uint8_t nandeccmode; /*1 */
25 uint16_t nandpagesize; /*2-3 */
26 uint32_t blocksize; /*4-7 */
27 uint32_t rsvd1; /*8-11 */
28 uint32_t srcaddr; /*12-15 */
29 uint32_t destaddr; /*16-19 */
30 uint32_t execaddr; /*20-23 */
31 uint8_t satapiomode; /*24 */
32 uint8_t rsvd3; /*25 */
33 uint16_t ddrinitdelay; /*26-27 */
34 uint16_t rsvd2; /*28-29 */
36 uint8_t checksum; /*31 */
39 struct ext_hdr_v0_reg {
44 #define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
48 uint8_t reserved[0x20 - sizeof(uint32_t)];
49 struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
54 /* Structure of the main header, version 1 (Armada 370, Armada XP) */
56 uint8_t blockid; /* 0 */
57 uint8_t reserved1; /* 1 */
58 uint16_t reserved2; /* 2-3 */
59 uint32_t blocksize; /* 4-7 */
60 uint8_t version; /* 8 */
61 uint8_t headersz_msb; /* 9 */
62 uint16_t headersz_lsb; /* A-B */
63 uint32_t srcaddr; /* C-F */
64 uint32_t destaddr; /* 10-13 */
65 uint32_t execaddr; /* 14-17 */
66 uint8_t reserved3; /* 18 */
67 uint8_t nandblocksize; /* 19 */
68 uint8_t nandbadblklocation; /* 1A */
69 uint8_t reserved4; /* 1B */
70 uint16_t reserved5; /* 1C-1D */
72 uint8_t checksum; /* 1F */
76 * Header for the optional headers, version 1 (Armada 370, Armada XP)
81 uint16_t headersz_lsb;
86 * Various values for the opt_hdr_v1->headertype field, describing the
87 * different types of optional headers. The "secure" header contains
88 * informations related to secure boot (encryption keys, etc.). The
89 * "binary" header contains ARM binary code to be executed prior to
90 * executing the main payload (usually the bootloader). This is
91 * typically used to execute DDR3 training code. The "register" header
92 * allows to describe a set of (address, value) tuples that are
93 * generally used to configure the DRAM controller.
95 #define OPT_HDR_V1_SECURE_TYPE 0x1
96 #define OPT_HDR_V1_BINARY_TYPE 0x2
97 #define OPT_HDR_V1_REGISTER_TYPE 0x3
99 #define KWBHEADER_V1_SIZE(hdr) \
100 (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
102 static struct image_cfg_element *image_cfg;
110 struct boot_mode boot_modes[] = {
120 struct nand_ecc_mode {
125 struct nand_ecc_mode nand_ecc_modes[] = {
129 { 0x03, "disabled" },
133 /* Used to identify an undefined execution or destination address */
134 #define ADDR_INVALID ((uint32_t)-1)
136 #define BINARY_MAX_ARGS 8
138 /* In-memory representation of a line of the configuration file */
139 struct image_cfg_element {
141 IMAGE_CFG_VERSION = 0x1,
145 IMAGE_CFG_NAND_BLKSZ,
146 IMAGE_CFG_NAND_BADBLK_LOCATION,
147 IMAGE_CFG_NAND_ECC_MODE,
148 IMAGE_CFG_NAND_PAGESZ,
154 unsigned int version;
155 unsigned int bootfrom;
158 unsigned int args[BINARY_MAX_ARGS];
162 unsigned int dstaddr;
163 unsigned int execaddr;
164 unsigned int nandblksz;
165 unsigned int nandbadblklocation;
166 unsigned int nandeccmode;
167 unsigned int nandpagesz;
168 struct ext_hdr_v0_reg regdata;
172 #define IMAGE_CFG_ELEMENT_MAX 256
175 * Byte 8 of the image header contains the version number. In the v0
176 * header, byte 8 was reserved, and always set to 0. In the v1 header,
177 * byte 8 has been changed to a proper field, set to 1.
179 static unsigned int image_version(void *header)
181 unsigned char *ptr = header;
186 * Utility functions to manipulate boot mode and ecc modes (convert
187 * them back and forth between description strings and the
188 * corresponding numerical identifiers).
191 static const char *image_boot_mode_name(unsigned int id)
194 for (i = 0; boot_modes[i].name; i++)
195 if (boot_modes[i].id == id)
196 return boot_modes[i].name;
200 int image_boot_mode_id(const char *boot_mode_name)
203 for (i = 0; boot_modes[i].name; i++)
204 if (!strcmp(boot_modes[i].name, boot_mode_name))
205 return boot_modes[i].id;
210 int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
213 for (i = 0; nand_ecc_modes[i].name; i++)
214 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
215 return nand_ecc_modes[i].id;
219 static struct image_cfg_element *
220 image_find_option(unsigned int optiontype)
224 for (i = 0; i < cfgn; i++) {
225 if (image_cfg[i].type == optiontype)
226 return &image_cfg[i];
233 image_count_options(unsigned int optiontype)
236 unsigned int count = 0;
238 for (i = 0; i < cfgn; i++)
239 if (image_cfg[i].type == optiontype)
246 * Compute a 8-bit checksum of a memory area. This algorithm follows
247 * the requirements of the Marvell SoC BootROM specifications.
249 static uint8_t image_checksum8(void *start, uint32_t len)
254 /* check len and return zero checksum if invalid */
266 static uint32_t image_checksum32(void *start, uint32_t len)
271 /* check len and return zero checksum if invalid */
275 if (len % sizeof(uint32_t)) {
276 fprintf(stderr, "Length %d is not in multiple of %zu\n",
277 len, sizeof(uint32_t));
284 len -= sizeof(uint32_t);
290 static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
293 struct image_cfg_element *e;
295 struct main_hdr_v0 *main_hdr;
296 struct ext_hdr_v0 *ext_hdr;
301 * Calculate the size of the header and the size of the
304 headersz = sizeof(struct main_hdr_v0);
306 if (image_count_options(IMAGE_CFG_DATA) > 0) {
308 headersz += sizeof(struct ext_hdr_v0);
311 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
312 fprintf(stderr, "More than one payload, not possible\n");
316 image = malloc(headersz);
318 fprintf(stderr, "Cannot allocate memory for image\n");
322 memset(image, 0, headersz);
326 /* Fill in the main header */
327 main_hdr->blocksize = payloadsz + sizeof(uint32_t);
328 main_hdr->srcaddr = headersz;
329 main_hdr->ext = has_ext;
330 main_hdr->destaddr = params->addr;
331 main_hdr->execaddr = params->ep;
333 e = image_find_option(IMAGE_CFG_BOOT_FROM);
335 main_hdr->blockid = e->bootfrom;
336 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
338 main_hdr->nandeccmode = e->nandeccmode;
339 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
341 main_hdr->nandpagesize = e->nandpagesz;
342 main_hdr->checksum = image_checksum8(image,
343 sizeof(struct main_hdr_v0));
345 /* Generate the ext header */
349 ext_hdr = image + sizeof(struct main_hdr_v0);
350 ext_hdr->offset = 0x40;
352 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
353 e = &image_cfg[cfgi];
354 if (e->type != IMAGE_CFG_DATA)
357 ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
358 ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
362 ext_hdr->checksum = image_checksum8(ext_hdr,
363 sizeof(struct ext_hdr_v0));
370 static size_t image_headersz_v1(struct image_tool_params *params,
373 struct image_cfg_element *binarye;
378 * Calculate the size of the header and the size of the
381 headersz = sizeof(struct main_hdr_v1);
383 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
384 fprintf(stderr, "More than one binary blob, not supported\n");
388 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
389 fprintf(stderr, "More than one payload, not possible\n");
393 binarye = image_find_option(IMAGE_CFG_BINARY);
397 ret = stat(binarye->binary.file, &s);
399 char *cwd = get_current_dir_name();
401 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
402 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
403 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
404 binarye->binary.file, cwd);
409 headersz += s.st_size +
410 binarye->binary.nargs * sizeof(unsigned int);
416 * The payload should be aligned on some reasonable
419 return ALIGN_SUP(headersz, 4096);
422 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
425 struct image_cfg_element *e, *binarye;
426 struct main_hdr_v1 *main_hdr;
433 * Calculate the size of the header and the size of the
436 headersz = image_headersz_v1(params, &hasext);
440 image = malloc(headersz);
442 fprintf(stderr, "Cannot allocate memory for image\n");
446 memset(image, 0, headersz);
448 cur = main_hdr = image;
449 cur += sizeof(struct main_hdr_v1);
451 /* Fill the main header */
452 main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t);
453 main_hdr->headersz_lsb = headersz & 0xFFFF;
454 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
455 main_hdr->destaddr = params->addr;
456 main_hdr->execaddr = params->ep;
457 main_hdr->srcaddr = headersz;
458 main_hdr->ext = hasext;
459 main_hdr->version = 1;
460 e = image_find_option(IMAGE_CFG_BOOT_FROM);
462 main_hdr->blockid = e->bootfrom;
463 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
465 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
466 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
468 main_hdr->nandbadblklocation = e->nandbadblklocation;
470 binarye = image_find_option(IMAGE_CFG_BINARY);
472 struct opt_hdr_v1 *hdr = cur;
479 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
481 bin = fopen(binarye->binary.file, "r");
483 fprintf(stderr, "Cannot open binary file %s\n",
484 binarye->binary.file);
488 fstat(fileno(bin), &s);
490 binhdrsz = sizeof(struct opt_hdr_v1) +
491 (binarye->binary.nargs + 1) * sizeof(unsigned int) +
493 hdr->headersz_lsb = binhdrsz & 0xFFFF;
494 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
496 cur += sizeof(struct opt_hdr_v1);
499 *args = binarye->binary.nargs;
501 for (argi = 0; argi < binarye->binary.nargs; argi++)
502 args[argi] = binarye->binary.args[argi];
504 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
506 ret = fread(cur, s.st_size, 1, bin);
509 "Could not read binary image %s\n",
510 binarye->binary.file);
519 * For now, we don't support more than one binary
520 * header, and no other header types are
521 * supported. So, the binary header is necessarily the
524 *((unsigned char *)cur) = 0;
526 cur += sizeof(uint32_t);
529 /* Calculate and set the header checksum */
530 main_hdr->checksum = image_checksum8(main_hdr, headersz);
536 static int image_create_config_parse_oneline(char *line,
537 struct image_cfg_element *el)
539 char *keyword, *saveptr;
540 char deliminiters[] = " \t";
542 keyword = strtok_r(line, deliminiters, &saveptr);
543 if (!strcmp(keyword, "VERSION")) {
544 char *value = strtok_r(NULL, deliminiters, &saveptr);
545 el->type = IMAGE_CFG_VERSION;
546 el->version = atoi(value);
547 } else if (!strcmp(keyword, "BOOT_FROM")) {
548 char *value = strtok_r(NULL, deliminiters, &saveptr);
549 el->type = IMAGE_CFG_BOOT_FROM;
550 el->bootfrom = image_boot_mode_id(value);
551 if (el->bootfrom < 0) {
553 "Invalid boot media '%s'\n", value);
556 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
557 char *value = strtok_r(NULL, deliminiters, &saveptr);
558 el->type = IMAGE_CFG_NAND_BLKSZ;
559 el->nandblksz = strtoul(value, NULL, 16);
560 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
561 char *value = strtok_r(NULL, deliminiters, &saveptr);
562 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
563 el->nandbadblklocation =
564 strtoul(value, NULL, 16);
565 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
566 char *value = strtok_r(NULL, deliminiters, &saveptr);
567 el->type = IMAGE_CFG_NAND_ECC_MODE;
568 el->nandeccmode = image_nand_ecc_mode_id(value);
569 if (el->nandeccmode < 0) {
571 "Invalid NAND ECC mode '%s'\n", value);
574 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
575 char *value = strtok_r(NULL, deliminiters, &saveptr);
576 el->type = IMAGE_CFG_NAND_PAGESZ;
577 el->nandpagesz = strtoul(value, NULL, 16);
578 } else if (!strcmp(keyword, "BINARY")) {
579 char *value = strtok_r(NULL, deliminiters, &saveptr);
582 el->type = IMAGE_CFG_BINARY;
583 el->binary.file = strdup(value);
585 value = strtok_r(NULL, deliminiters, &saveptr);
588 el->binary.args[argi] = strtoul(value, NULL, 16);
590 if (argi >= BINARY_MAX_ARGS) {
592 "Too many argument for binary\n");
596 el->binary.nargs = argi;
597 } else if (!strcmp(keyword, "DATA")) {
598 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
599 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
601 if (!value1 || !value2) {
603 "Invalid number of arguments for DATA\n");
607 el->type = IMAGE_CFG_DATA;
608 el->regdata.raddr = strtoul(value1, NULL, 16);
609 el->regdata.rdata = strtoul(value2, NULL, 16);
611 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
618 * Parse the configuration file 'fcfg' into the array of configuration
619 * elements 'image_cfg', and return the number of configuration
620 * elements in 'cfgn'.
622 static int image_create_config_parse(FILE *fcfg)
627 /* Parse the configuration file */
628 while (!feof(fcfg)) {
632 /* Read the current line */
633 memset(buf, 0, sizeof(buf));
634 line = fgets(buf, sizeof(buf), fcfg);
638 /* Ignore useless lines */
639 if (line[0] == '\n' || line[0] == '#')
642 /* Strip final newline */
643 if (line[strlen(line) - 1] == '\n')
644 line[strlen(line) - 1] = 0;
646 /* Parse the current line */
647 ret = image_create_config_parse_oneline(line,
654 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
656 "Too many configuration elements in .cfg file\n");
665 static int image_get_version(void)
667 struct image_cfg_element *e;
669 e = image_find_option(IMAGE_CFG_VERSION);
676 static int image_version_file(const char *input)
682 fcfg = fopen(input, "r");
684 fprintf(stderr, "Could not open input file %s\n", input);
688 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
689 sizeof(struct image_cfg_element));
691 fprintf(stderr, "Cannot allocate memory\n");
697 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
700 ret = image_create_config_parse(fcfg);
707 version = image_get_version();
708 /* Fallback to version 0 is no version is provided in the cfg file */
717 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
718 struct image_tool_params *params)
728 fcfg = fopen(params->imagename, "r");
730 fprintf(stderr, "Could not open input file %s\n",
735 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
736 sizeof(struct image_cfg_element));
738 fprintf(stderr, "Cannot allocate memory\n");
744 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
747 ret = image_create_config_parse(fcfg);
754 version = image_get_version();
755 /* Fallback to version 0 is no version is provided in the cfg file */
760 image = image_create_v0(&headersz, params, sbuf->st_size);
761 else if (version == 1)
762 image = image_create_v1(&headersz, params, sbuf->st_size);
765 fprintf(stderr, "Could not create image\n");
772 /* Build and add image checksum header */
773 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
774 size = write(ifd, &checksum, sizeof(uint32_t));
775 if (size != sizeof(uint32_t)) {
776 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
777 params->cmdname, size, params->imagefile);
781 sbuf->st_size += sizeof(uint32_t);
783 /* Finally copy the header into the image area */
784 memcpy(ptr, image, headersz);
789 static void kwbimage_print_header(const void *ptr)
791 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
793 printf("Image Type: MVEBU Boot from %s Image\n",
794 image_boot_mode_name(mhdr->blockid));
795 printf("Data Size: ");
796 printf("Image version:%d\n", image_version((void *)ptr));
797 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
798 printf("Load Address: %08x\n", mhdr->destaddr);
799 printf("Entry Point: %08x\n", mhdr->execaddr);
802 static int kwbimage_check_image_types(uint8_t type)
804 if (type == IH_TYPE_KWBIMAGE)
810 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
811 struct image_tool_params *params)
813 struct main_hdr_v0 *main_hdr;
814 struct ext_hdr_v0 *ext_hdr;
817 main_hdr = (void *)ptr;
818 checksum = image_checksum8(ptr,
819 sizeof(struct main_hdr_v0));
820 if (checksum != main_hdr->checksum)
821 return -FDT_ERR_BADSTRUCTURE;
823 /* Only version 0 extended header has checksum */
824 if (image_version((void *)ptr) == 0) {
825 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
826 checksum = image_checksum8(ext_hdr,
827 sizeof(struct ext_hdr_v0));
828 if (checksum != ext_hdr->checksum)
829 return -FDT_ERR_BADSTRUCTURE;
835 static int kwbimage_generate(struct image_tool_params *params,
836 struct image_type_params *tparams)
842 version = image_version_file(params->imagename);
844 alloc_len = sizeof(struct main_hdr_v0) +
845 sizeof(struct ext_hdr_v0);
847 alloc_len = image_headersz_v1(params, NULL);
850 hdr = malloc(alloc_len);
852 fprintf(stderr, "%s: malloc return failure: %s\n",
853 params->cmdname, strerror(errno));
857 memset(hdr, 0, alloc_len);
858 tparams->header_size = alloc_len;
865 * Report Error if xflag is set in addition to default
867 static int kwbimage_check_params(struct image_tool_params *params)
869 if (!strlen(params->imagename)) {
870 fprintf(stderr, "Error:%s - Configuration file not specified, "
871 "it is needed for kwbimage generation\n",
876 return (params->dflag && (params->fflag || params->lflag)) ||
877 (params->fflag && (params->dflag || params->lflag)) ||
878 (params->lflag && (params->dflag || params->fflag)) ||
879 (params->xflag) || !(strlen(params->imagename));
883 * kwbimage type parameters definition
885 static struct image_type_params kwbimage_params = {
886 .name = "Marvell MVEBU Boot Image support",
887 .header_size = 0, /* no fixed header size */
889 .vrec_header = kwbimage_generate,
890 .check_image_type = kwbimage_check_image_types,
891 .verify_header = kwbimage_verify_header,
892 .print_header = kwbimage_print_header,
893 .set_header = kwbimage_set_header,
894 .check_params = kwbimage_check_params,
897 void init_kwb_image_type (void)
899 register_image_type(&kwbimage_params);