]> Git Repo - J-u-boot.git/blobdiff - tools/kwbimage.c
tools: kwbimage: Set BOOT_FROM by default to SPI
[J-u-boot.git] / tools / kwbimage.c
index 00cb338d64fcaa3697bc53d234b1ede20c89c5e4..38b6e2fed201c5fdb8c7435b54dc0759f4607c3a 100644 (file)
@@ -1,12 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Image manipulator for Marvell SoCs
- *  supports Kirkwood, Dove, Armada 370, Armada XP, and Armada 38x
+ *  supports Kirkwood, Dove, Armada 370, Armada XP, Armada 375, Armada 38x and
+ *  Armada 39x
  *
  * (C) Copyright 2013 Thomas Petazzoni
- *
- * Not implemented: support for the register headers in v1 images
  */
 
 #include "imagetool.h"
@@ -59,13 +58,13 @@ struct hash_v1 {
 };
 
 struct boot_mode boot_modes[] = {
-       { 0x4D, "i2c"  },
-       { 0x5A, "spi"  },
-       { 0x8B, "nand" },
-       { 0x78, "sata" },
-       { 0x9C, "pex"  },
-       { 0x69, "uart" },
-       { 0xAE, "sdio" },
+       { IBR_HDR_I2C_ID, "i2c"  },
+       { IBR_HDR_SPI_ID, "spi"  },
+       { IBR_HDR_NAND_ID, "nand" },
+       { IBR_HDR_SATA_ID, "sata" },
+       { IBR_HDR_PEX_ID, "pex"  },
+       { IBR_HDR_UART_ID, "uart" },
+       { IBR_HDR_SDIO_ID, "sdio" },
        {},
 };
 
@@ -75,10 +74,10 @@ struct nand_ecc_mode {
 };
 
 struct nand_ecc_mode nand_ecc_modes[] = {
-       { 0x00, "default" },
-       { 0x01, "hamming" },
-       { 0x02, "rs" },
-       { 0x03, "disabled" },
+       { IBR_HDR_ECC_DEFAULT, "default" },
+       { IBR_HDR_ECC_FORCED_HAMMING, "hamming" },
+       { IBR_HDR_ECC_FORCED_RS, "rs" },
+       { IBR_HDR_ECC_DISABLED, "disabled" },
        {},
 };
 
@@ -102,6 +101,8 @@ enum image_cfg_type {
        IMAGE_CFG_DATA,
        IMAGE_CFG_DATA_DELAY,
        IMAGE_CFG_BAUDRATE,
+       IMAGE_CFG_UART_PORT,
+       IMAGE_CFG_UART_MPP,
        IMAGE_CFG_DEBUG,
        IMAGE_CFG_KAK,
        IMAGE_CFG_CSK,
@@ -130,6 +131,8 @@ static const char * const id_strs[] = {
        [IMAGE_CFG_DATA] = "DATA",
        [IMAGE_CFG_DATA_DELAY] = "DATA_DELAY",
        [IMAGE_CFG_BAUDRATE] = "BAUDRATE",
+       [IMAGE_CFG_UART_PORT] = "UART_PORT",
+       [IMAGE_CFG_UART_MPP] = "UART_MPP",
        [IMAGE_CFG_DEBUG] = "DEBUG",
        [IMAGE_CFG_KAK] = "KAK",
        [IMAGE_CFG_CSK] = "CSK",
@@ -162,6 +165,8 @@ struct image_cfg_element {
                struct ext_hdr_v0_reg regdata;
                unsigned int regdata_delay;
                unsigned int baudrate;
+               unsigned int uart_port;
+               unsigned int uart_mpp;
                unsigned int debug;
                const char *key_name;
                int csk_idx;
@@ -261,6 +266,18 @@ static bool image_get_spezialized_img(void)
        return e->sec_specialized_img;
 }
 
+static int image_get_bootfrom(void)
+{
+       struct image_cfg_element *e;
+
+       e = image_find_option(IMAGE_CFG_BOOT_FROM);
+       if (!e)
+               /* fallback to SPI if no BOOT_FROM is not provided */
+               return IBR_HDR_SPI_ID;
+
+       return e->bootfrom;
+}
+
 /*
  * Compute a 8-bit checksum of a memory area. This algorithm follows
  * the requirements of the Marvell SoC BootROM specifications.
@@ -282,14 +299,6 @@ static uint8_t image_checksum8(void *start, uint32_t len)
        return csum;
 }
 
-size_t kwbimage_header_size(unsigned char *ptr)
-{
-       if (image_version((void *)ptr) == 0)
-               return sizeof(struct main_hdr_v0);
-       else
-               return KWBHEADER_V1_SIZE((struct main_hdr_v1 *)ptr);
-}
-
 /*
  * Verify checksum over a complete header that includes the checksum field.
  * Return 1 when OK, otherwise 0.
@@ -300,7 +309,7 @@ static int main_hdr_checksum_ok(void *hdr)
        struct main_hdr_v0 *main_hdr = (struct main_hdr_v0 *)hdr;
        uint8_t checksum;
 
-       checksum = image_checksum8(hdr, kwbimage_header_size(hdr));
+       checksum = image_checksum8(hdr, kwbheader_size_for_csum(hdr));
        /* Calculated checksum includes the header checksum field. Compensate
         * for that.
         */
@@ -544,7 +553,7 @@ static int kwb_export_pubkey(RSA *key, struct pubkey_der_v1 *dst, FILE *hashf,
        }
 
        if (4 + size_seq > sizeof(dst->key)) {
-               fprintf(stderr, "export pk failed: seq too large (%d, %lu)\n",
+               fprintf(stderr, "export pk failed: seq too large (%d, %zu)\n",
                        4 + size_seq, sizeof(dst->key));
                fprintf(stderr, errmsg, keyname);
                return -ENOBUFS;
@@ -832,6 +841,12 @@ static int kwb_dump_fuse_cmds(struct secure_hdr_v1 *sec_hdr)
        if (!strcmp(e->name, "a38x")) {
                FILE *out = fopen("kwb_fuses_a38x.txt", "w+");
 
+               if (!out) {
+                       fprintf(stderr, "Couldn't open eFuse settings: '%s': %s\n",
+                               "kwb_fuses_a38x.txt", strerror(errno));
+                       return -ENOENT;
+               }
+
                kwb_dump_fuse_cmds_38x(out, sec_hdr);
                fclose(out);
                goto done;
@@ -878,12 +893,11 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
                cpu_to_le32(payloadsz - headersz);
        main_hdr->srcaddr   = cpu_to_le32(headersz);
        main_hdr->ext       = has_ext;
+       main_hdr->version   = 0;
        main_hdr->destaddr  = cpu_to_le32(params->addr);
        main_hdr->execaddr  = cpu_to_le32(params->ep);
+       main_hdr->blockid   = image_get_bootfrom();
 
-       e = image_find_option(IMAGE_CFG_BOOT_FROM);
-       if (e)
-               main_hdr->blockid = e->bootfrom;
        e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
        if (e)
                main_hdr->nandeccmode = e->nandeccmode;
@@ -935,6 +949,12 @@ static size_t image_headersz_v1(int *hasext)
         */
        headersz = sizeof(struct main_hdr_v1);
 
+       if (image_get_csk_index() >= 0) {
+               headersz += sizeof(struct secure_hdr_v1);
+               if (hasext)
+                       *hasext = 1;
+       }
+
        count = image_count_options(IMAGE_CFG_DATA);
        if (count > 0)
                headersz += sizeof(struct register_set_hdr_v1) + 8 * count + 4;
@@ -966,15 +986,10 @@ static size_t image_headersz_v1(int *hasext)
                        return 0;
                }
 
-               headersz += sizeof(struct opt_hdr_v1) +
-                       ALIGN(s.st_size, 4) +
-                       (binarye->binary.nargs + 2) * sizeof(uint32_t);
-               if (hasext)
-                       *hasext = 1;
-       }
-
-       if (image_get_csk_index() >= 0) {
-               headersz += sizeof(struct secure_hdr_v1);
+               headersz += sizeof(struct opt_hdr_v1) + sizeof(uint32_t) +
+                       (binarye->binary.nargs) * sizeof(uint32_t);
+               headersz = ALIGN(headersz, 16);
+               headersz += ALIGN(s.st_size, 4) + sizeof(uint32_t);
                if (hasext)
                        *hasext = 1;
        }
@@ -987,9 +1002,12 @@ static size_t image_headersz_v1(int *hasext)
 }
 
 int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
-                        struct image_cfg_element *binarye)
+                        struct image_cfg_element *binarye,
+                        struct main_hdr_v1 *main_hdr)
 {
        struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)*cur;
+       uint32_t add_args;
+       uint32_t offset;
        uint32_t *args;
        size_t binhdrsz;
        struct stat s;
@@ -1012,12 +1030,6 @@ int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
                goto err_close;
        }
 
-       binhdrsz = sizeof(struct opt_hdr_v1) +
-               (binarye->binary.nargs + 2) * sizeof(uint32_t) +
-               ALIGN(s.st_size, 4);
-       hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
-       hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
-
        *cur += sizeof(struct opt_hdr_v1);
 
        args = (uint32_t *)*cur;
@@ -1028,6 +1040,19 @@ int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
 
        *cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
 
+       /*
+        * ARM executable code inside the BIN header on some mvebu platforms
+        * (e.g. A370, AXP) must always be aligned with the 128-bit boundary.
+        * This requirement can be met by inserting dummy arguments into
+        * BIN header, if needed.
+        */
+       offset = *cur - (uint8_t *)main_hdr;
+       add_args = ((16 - offset % 16) % 16) / sizeof(uint32_t);
+       if (add_args) {
+               *(args - 1) = cpu_to_le32(binarye->binary.nargs + add_args);
+               *cur += add_args * sizeof(uint32_t);
+       }
+
        ret = fread(*cur, s.st_size, 1, bin);
        if (ret != 1) {
                fprintf(stderr,
@@ -1046,6 +1071,12 @@ int add_binary_header_v1(uint8_t **cur, uint8_t **next_ext,
 
        *cur += sizeof(uint32_t);
 
+       binhdrsz = sizeof(struct opt_hdr_v1) +
+               (binarye->binary.nargs + add_args + 2) * sizeof(uint32_t) +
+               ALIGN(s.st_size, 4);
+       hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
+       hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
+
        return 0;
 
 err_close:
@@ -1060,6 +1091,11 @@ int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr)
        int res;
 
        hashf = fopen("pub_kak_hash.txt", "w");
+       if (!hashf) {
+               fprintf(stderr, "Couldn't open hash file: '%s': %s\n",
+                       "pub_kak_hash.txt", strerror(errno));
+               return 1;
+       }
 
        res = kwb_export_pubkey(kak, &secure_hdr->kak, hashf, "KAK");
 
@@ -1076,7 +1112,7 @@ int kwb_sign_csk_with_kak(struct image_tool_params *params,
        int csk_idx = image_get_csk_index();
        struct sig_v1 tmp_sig;
 
-       if (csk_idx >= 16) {
+       if (csk_idx < 0 || csk_idx > 15) {
                fprintf(stderr, "Invalid CSK index %d\n", csk_idx);
                return 1;
        }
@@ -1206,18 +1242,26 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
        main_hdr->srcaddr      = cpu_to_le32(headersz);
        main_hdr->ext          = hasext;
        main_hdr->version      = 1;
-       e = image_find_option(IMAGE_CFG_BOOT_FROM);
-       if (e)
-               main_hdr->blockid = e->bootfrom;
+       main_hdr->blockid      = image_get_bootfrom();
+
        e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
        if (e)
                main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
+       e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
+       if (e)
+               main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
        e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
        if (e)
                main_hdr->nandbadblklocation = e->nandbadblklocation;
        e = image_find_option(IMAGE_CFG_BAUDRATE);
        if (e)
-               main_hdr->options = baudrate_to_option(e->baudrate);
+               main_hdr->options |= baudrate_to_option(e->baudrate);
+       e = image_find_option(IMAGE_CFG_UART_PORT);
+       if (e)
+               main_hdr->options |= (e->uart_port & 3) << 3;
+       e = image_find_option(IMAGE_CFG_UART_MPP);
+       if (e)
+               main_hdr->options |= (e->uart_mpp & 7) << 5;
        e = image_find_option(IMAGE_CFG_DEBUG);
        if (e)
                main_hdr->flags = e->debug ? 0x1 : 0;
@@ -1297,7 +1341,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
                if (e->type != IMAGE_CFG_BINARY)
                        continue;
 
-               if (add_binary_header_v1(&cur, &next_ext, e))
+               if (add_binary_header_v1(&cur, &next_ext, e, main_hdr))
                        return NULL;
        }
 
@@ -1419,6 +1463,12 @@ static int image_create_config_parse_oneline(char *line,
        case IMAGE_CFG_BAUDRATE:
                el->baudrate = strtoul(value1, NULL, 10);
                break;
+       case IMAGE_CFG_UART_PORT:
+               el->uart_port = strtoul(value1, NULL, 16);
+               break;
+       case IMAGE_CFG_UART_MPP:
+               el->uart_mpp = strtoul(value1, NULL, 16);
+               break;
        case IMAGE_CFG_DEBUG:
                el->debug = strtoul(value1, NULL, 10);
                break;
@@ -1518,17 +1568,6 @@ static int image_get_version(void)
        return e->version;
 }
 
-static int image_get_bootfrom(void)
-{
-       struct image_cfg_element *e;
-
-       e = image_find_option(IMAGE_CFG_BOOT_FROM);
-       if (!e)
-               return -1;
-
-       return e->bootfrom;
-}
-
 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
                                struct image_tool_params *params)
 {
@@ -1609,34 +1648,20 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
 static void kwbimage_print_header(const void *ptr)
 {
        struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
+       struct opt_hdr_v1 *ohdr;
 
        printf("Image Type:   MVEBU Boot from %s Image\n",
               image_boot_mode_name(mhdr->blockid));
-       printf("Image version:%d\n", image_version((void *)ptr));
-       if (image_version((void *)ptr) == 1) {
-               struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
+       printf("Image version:%d\n", kwbimage_version(ptr));
 
-               if (mhdr->ext & 0x1) {
-                       struct opt_hdr_v1 *ohdr = (struct opt_hdr_v1 *)
-                                                 ((uint8_t *)ptr +
-                                                  sizeof(*mhdr));
-
-                       while (1) {
-                               uint32_t ohdr_size;
-
-                               ohdr_size = (ohdr->headersz_msb << 16) |
-                                           le16_to_cpu(ohdr->headersz_lsb);
-                               if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
-                                       printf("BIN Hdr Size: ");
-                                       genimg_print_size(ohdr_size - 12 - 4 * ohdr->data[0]);
-                               }
-                               if (!(*((uint8_t *)ohdr + ohdr_size - 4) & 0x1))
-                                       break;
-                               ohdr = (struct opt_hdr_v1 *)((uint8_t *)ohdr +
-                                                            ohdr_size);
-                       }
+       for_each_opt_hdr_v1 (ohdr, mhdr) {
+               if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
+                       printf("BIN Hdr Size: ");
+                       genimg_print_size(opt_hdr_v1_size(ohdr) - 12 -
+                                         4 * ohdr->data[0]);
                }
        }
+
        printf("Data Size:    ");
        genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
        printf("Load Address: %08x\n", mhdr->destaddr);
@@ -1654,8 +1679,8 @@ static int kwbimage_check_image_types(uint8_t type)
 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
                                  struct image_tool_params *params)
 {
-       uint8_t checksum;
-       size_t header_size = kwbimage_header_size(ptr);
+       size_t header_size = kwbheader_size(ptr);
+       uint8_t csum;
 
        if (header_size > image_size)
                return -FDT_ERR_BADSTRUCTURE;
@@ -1664,51 +1689,27 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size,
                return -FDT_ERR_BADSTRUCTURE;
 
        /* Only version 0 extended header has checksum */
-       if (image_version((void *)ptr) == 0) {
+       if (kwbimage_version(ptr) == 0) {
                struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
 
                if (mhdr->ext & 0x1) {
-                       struct ext_hdr_v0 *ext_hdr;
-
-                       ext_hdr = (struct ext_hdr_v0 *)
-                               (ptr + sizeof(struct main_hdr_v0));
-                       checksum = image_checksum8(ext_hdr,
-                                                  sizeof(struct ext_hdr_v0)
-                                                  - sizeof(uint8_t));
-                       if (checksum != ext_hdr->checksum)
+                       struct ext_hdr_v0 *ext_hdr = (void *)(mhdr + 1);
+
+                       csum = image_checksum8(ext_hdr, sizeof(*ext_hdr) - 1);
+                       if (csum != ext_hdr->checksum)
                                return -FDT_ERR_BADSTRUCTURE;
                }
-       }
-
-       if (image_version((void *)ptr) == 1) {
+       } else if (kwbimage_version(ptr) == 1) {
                struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
+               const uint8_t *mhdr_end;
+               struct opt_hdr_v1 *ohdr;
                uint32_t offset;
                uint32_t size;
 
-               if (mhdr->ext & 0x1) {
-                       uint32_t ohdr_size;
-                       struct opt_hdr_v1 *ohdr = (struct opt_hdr_v1 *)
-                                                 (ptr + sizeof(*mhdr));
-
-                       while (1) {
-                               if ((uint8_t *)ohdr + sizeof(*ohdr) >
-                                   (uint8_t *)mhdr + header_size)
-                                       return -FDT_ERR_BADSTRUCTURE;
-
-                               ohdr_size = (ohdr->headersz_msb << 16) |
-                                           le16_to_cpu(ohdr->headersz_lsb);
-
-                               if (ohdr_size < 8 ||
-                                   (uint8_t *)ohdr + ohdr_size >
-                                   (uint8_t *)mhdr + header_size)
-                                       return -FDT_ERR_BADSTRUCTURE;
-
-                               if (!(*((uint8_t *)ohdr + ohdr_size - 4) & 0x1))
-                                       break;
-                               ohdr = (struct opt_hdr_v1 *)((uint8_t *)ohdr +
-                                                            ohdr_size);
-                       }
-               }
+               mhdr_end = (uint8_t *)mhdr + header_size;
+               for_each_opt_hdr_v1 (ohdr, ptr)
+                       if (!opt_hdr_v1_valid_size(ohdr, mhdr_end))
+                               return -FDT_ERR_BADSTRUCTURE;
 
                offset = le32_to_cpu(mhdr->srcaddr);
 
@@ -1744,12 +1745,14 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size,
                        return -FDT_ERR_BADSTRUCTURE;
 
                size = le32_to_cpu(mhdr->blocksize);
-               if (offset + size > image_size || size % 4 != 0)
+               if (size < 4 || offset + size > image_size || size % 4 != 0)
                        return -FDT_ERR_BADSTRUCTURE;
 
                if (image_checksum32(ptr + offset, size - 4) !=
                    *(uint32_t *)(ptr + offset + size - 4))
                        return -FDT_ERR_BADSTRUCTURE;
+       } else {
+               return -FDT_ERR_BADSTRUCTURE;
        }
 
        return 0;
@@ -1852,37 +1855,25 @@ static int kwbimage_generate(struct image_tool_params *params,
 static int kwbimage_extract_subimage(void *ptr, struct image_tool_params *params)
 {
        struct main_hdr_v1 *mhdr = (struct main_hdr_v1 *)ptr;
-       size_t header_size = kwbimage_header_size(ptr);
+       size_t header_size = kwbheader_size(ptr);
+       struct opt_hdr_v1 *ohdr;
        int idx = params->pflag;
        int cur_idx = 0;
        uint32_t offset;
        ulong image;
        ulong size;
 
-       if (image_version((void *)ptr) == 1 && (mhdr->ext & 0x1)) {
-               struct opt_hdr_v1 *ohdr = (struct opt_hdr_v1 *)
-                                         ((uint8_t *)ptr +
-                                          sizeof(*mhdr));
+       for_each_opt_hdr_v1 (ohdr, ptr) {
+               if (ohdr->headertype != OPT_HDR_V1_BINARY_TYPE)
+                       continue;
 
-               while (1) {
-                       uint32_t ohdr_size = (ohdr->headersz_msb << 16) |
-                                            le16_to_cpu(ohdr->headersz_lsb);
-
-                       if (ohdr->headertype == OPT_HDR_V1_BINARY_TYPE) {
-                               if (idx == cur_idx) {
-                                       image = (ulong)&ohdr->data[4 +
-                                                4 * ohdr->data[0]];
-                                       size = ohdr_size - 12 -
-                                              4 * ohdr->data[0];
-                                       goto extract;
-                               }
-                               ++cur_idx;
-                       }
-                       if (!(*((uint8_t *)ohdr + ohdr_size - 4) & 0x1))
-                               break;
-                       ohdr = (struct opt_hdr_v1 *)((uint8_t *)ohdr +
-                                                    ohdr_size);
+               if (idx == cur_idx) {
+                       image = (ulong)&ohdr->data[4 + 4 * ohdr->data[0]];
+                       size = opt_hdr_v1_size(ohdr) - 12 - 4 * ohdr->data[0];
+                       goto extract;
                }
+
+               ++cur_idx;
        }
 
        if (idx != cur_idx) {
This page took 0.041454 seconds and 4 git commands to generate.