uboot/tools/kwbimage.c
<<
>>
Prefs
   1/*
   2 * Image manipulator for Marvell SoCs
   3 *  supports Kirkwood, Dove, Armada 370, and Armada XP
   4 *
   5 * (C) Copyright 2013 Thomas Petazzoni
   6 * <thomas.petazzoni@free-electrons.com>
   7 *
   8 * SPDX-License-Identifier:     GPL-2.0+
   9 *
  10 * Not implemented: support for the register headers and secure
  11 * headers in v1 images
  12 */
  13
  14#include "imagetool.h"
  15#include <limits.h>
  16#include <image.h>
  17#include <stdint.h>
  18#include "kwbimage.h"
  19
  20#define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
  21
  22/* Structure of the main header, version 0 (Kirkwood, Dove) */
  23struct main_hdr_v0 {
  24        uint8_t  blockid;               /*0     */
  25        uint8_t  nandeccmode;           /*1     */
  26        uint16_t nandpagesize;          /*2-3   */
  27        uint32_t blocksize;             /*4-7   */
  28        uint32_t rsvd1;                 /*8-11  */
  29        uint32_t srcaddr;               /*12-15 */
  30        uint32_t destaddr;              /*16-19 */
  31        uint32_t execaddr;              /*20-23 */
  32        uint8_t  satapiomode;           /*24    */
  33        uint8_t  rsvd3;                 /*25    */
  34        uint16_t ddrinitdelay;          /*26-27 */
  35        uint16_t rsvd2;                 /*28-29 */
  36        uint8_t  ext;                   /*30    */
  37        uint8_t  checksum;              /*31    */
  38};
  39
  40struct ext_hdr_v0_reg {
  41        uint32_t raddr;
  42        uint32_t rdata;
  43};
  44
  45#define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
  46
  47struct ext_hdr_v0 {
  48        uint32_t              offset;
  49        uint8_t               reserved[0x20 - sizeof(uint32_t)];
  50        struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
  51        uint8_t               reserved2[7];
  52        uint8_t               checksum;
  53};
  54
  55/* Structure of the main header, version 1 (Armada 370, Armada XP) */
  56struct main_hdr_v1 {
  57        uint8_t  blockid;               /* 0 */
  58        uint8_t  reserved1;             /* 1 */
  59        uint16_t reserved2;             /* 2-3 */
  60        uint32_t blocksize;             /* 4-7 */
  61        uint8_t  version;               /* 8 */
  62        uint8_t  headersz_msb;          /* 9 */
  63        uint16_t headersz_lsb;          /* A-B */
  64        uint32_t srcaddr;               /* C-F */
  65        uint32_t destaddr;              /* 10-13 */
  66        uint32_t execaddr;              /* 14-17 */
  67        uint8_t  reserved3;             /* 18 */
  68        uint8_t  nandblocksize;         /* 19 */
  69        uint8_t  nandbadblklocation;    /* 1A */
  70        uint8_t  reserved4;             /* 1B */
  71        uint16_t reserved5;             /* 1C-1D */
  72        uint8_t  ext;                   /* 1E */
  73        uint8_t  checksum;              /* 1F */
  74};
  75
  76/*
  77 * Header for the optional headers, version 1 (Armada 370, Armada XP)
  78 */
  79struct opt_hdr_v1 {
  80        uint8_t  headertype;
  81        uint8_t  headersz_msb;
  82        uint16_t headersz_lsb;
  83        char     data[0];
  84};
  85
  86/*
  87 * Various values for the opt_hdr_v1->headertype field, describing the
  88 * different types of optional headers. The "secure" header contains
  89 * informations related to secure boot (encryption keys, etc.). The
  90 * "binary" header contains ARM binary code to be executed prior to
  91 * executing the main payload (usually the bootloader). This is
  92 * typically used to execute DDR3 training code. The "register" header
  93 * allows to describe a set of (address, value) tuples that are
  94 * generally used to configure the DRAM controller.
  95 */
  96#define OPT_HDR_V1_SECURE_TYPE   0x1
  97#define OPT_HDR_V1_BINARY_TYPE   0x2
  98#define OPT_HDR_V1_REGISTER_TYPE 0x3
  99
 100#define KWBHEADER_V1_SIZE(hdr) \
 101        (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
 102
 103static struct image_cfg_element *image_cfg;
 104static int cfgn;
 105
 106struct boot_mode {
 107        unsigned int id;
 108        const char *name;
 109};
 110
 111struct boot_mode boot_modes[] = {
 112        { 0x4D, "i2c"  },
 113        { 0x5A, "spi"  },
 114        { 0x8B, "nand" },
 115        { 0x78, "sata" },
 116        { 0x9C, "pex"  },
 117        { 0x69, "uart" },
 118        {},
 119};
 120
 121struct nand_ecc_mode {
 122        unsigned int id;
 123        const char *name;
 124};
 125
 126struct nand_ecc_mode nand_ecc_modes[] = {
 127        { 0x00, "default" },
 128        { 0x01, "hamming" },
 129        { 0x02, "rs" },
 130        { 0x03, "disabled" },
 131        {},
 132};
 133
 134/* Used to identify an undefined execution or destination address */
 135#define ADDR_INVALID ((uint32_t)-1)
 136
 137#define BINARY_MAX_ARGS 8
 138
 139/* In-memory representation of a line of the configuration file */
 140struct image_cfg_element {
 141        enum {
 142                IMAGE_CFG_VERSION = 0x1,
 143                IMAGE_CFG_BOOT_FROM,
 144                IMAGE_CFG_DEST_ADDR,
 145                IMAGE_CFG_EXEC_ADDR,
 146                IMAGE_CFG_NAND_BLKSZ,
 147                IMAGE_CFG_NAND_BADBLK_LOCATION,
 148                IMAGE_CFG_NAND_ECC_MODE,
 149                IMAGE_CFG_NAND_PAGESZ,
 150                IMAGE_CFG_BINARY,
 151                IMAGE_CFG_PAYLOAD,
 152                IMAGE_CFG_DATA,
 153        } type;
 154        union {
 155                unsigned int version;
 156                unsigned int bootfrom;
 157                struct {
 158                        const char *file;
 159                        unsigned int args[BINARY_MAX_ARGS];
 160                        unsigned int nargs;
 161                } binary;
 162                const char *payload;
 163                unsigned int dstaddr;
 164                unsigned int execaddr;
 165                unsigned int nandblksz;
 166                unsigned int nandbadblklocation;
 167                unsigned int nandeccmode;
 168                unsigned int nandpagesz;
 169                struct ext_hdr_v0_reg regdata;
 170        };
 171};
 172
 173#define IMAGE_CFG_ELEMENT_MAX 256
 174
 175/*
 176 * Byte 8 of the image header contains the version number. In the v0
 177 * header, byte 8 was reserved, and always set to 0. In the v1 header,
 178 * byte 8 has been changed to a proper field, set to 1.
 179 */
 180static unsigned int image_version(void *header)
 181{
 182        unsigned char *ptr = header;
 183        return ptr[8];
 184}
 185
 186/*
 187 * Utility functions to manipulate boot mode and ecc modes (convert
 188 * them back and forth between description strings and the
 189 * corresponding numerical identifiers).
 190 */
 191
 192static const char *image_boot_mode_name(unsigned int id)
 193{
 194        int i;
 195        for (i = 0; boot_modes[i].name; i++)
 196                if (boot_modes[i].id == id)
 197                        return boot_modes[i].name;
 198        return NULL;
 199}
 200
 201int image_boot_mode_id(const char *boot_mode_name)
 202{
 203        int i;
 204        for (i = 0; boot_modes[i].name; i++)
 205                if (!strcmp(boot_modes[i].name, boot_mode_name))
 206                        return boot_modes[i].id;
 207
 208        return -1;
 209}
 210
 211int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
 212{
 213        int i;
 214        for (i = 0; nand_ecc_modes[i].name; i++)
 215                if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
 216                        return nand_ecc_modes[i].id;
 217        return -1;
 218}
 219
 220static struct image_cfg_element *
 221image_find_option(unsigned int optiontype)
 222{
 223        int i;
 224
 225        for (i = 0; i < cfgn; i++) {
 226                if (image_cfg[i].type == optiontype)
 227                        return &image_cfg[i];
 228        }
 229
 230        return NULL;
 231}
 232
 233static unsigned int
 234image_count_options(unsigned int optiontype)
 235{
 236        int i;
 237        unsigned int count = 0;
 238
 239        for (i = 0; i < cfgn; i++)
 240                if (image_cfg[i].type == optiontype)
 241                        count++;
 242
 243        return count;
 244}
 245
 246/*
 247 * Compute a 8-bit checksum of a memory area. This algorithm follows
 248 * the requirements of the Marvell SoC BootROM specifications.
 249 */
 250static uint8_t image_checksum8(void *start, uint32_t len)
 251{
 252        uint8_t csum = 0;
 253        uint8_t *p = start;
 254
 255        /* check len and return zero checksum if invalid */
 256        if (!len)
 257                return 0;
 258
 259        do {
 260                csum += *p;
 261                p++;
 262        } while (--len);
 263
 264        return csum;
 265}
 266
 267static uint32_t image_checksum32(void *start, uint32_t len)
 268{
 269        uint32_t csum = 0;
 270        uint32_t *p = start;
 271
 272        /* check len and return zero checksum if invalid */
 273        if (!len)
 274                return 0;
 275
 276        if (len % sizeof(uint32_t)) {
 277                fprintf(stderr, "Length %d is not in multiple of %zu\n",
 278                        len, sizeof(uint32_t));
 279                return 0;
 280        }
 281
 282        do {
 283                csum += *p;
 284                p++;
 285                len -= sizeof(uint32_t);
 286        } while (len > 0);
 287
 288        return csum;
 289}
 290
 291static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
 292                             int payloadsz)
 293{
 294        struct image_cfg_element *e;
 295        size_t headersz;
 296        struct main_hdr_v0 *main_hdr;
 297        struct ext_hdr_v0 *ext_hdr;
 298        void *image;
 299        int has_ext = 0;
 300
 301        /*
 302         * Calculate the size of the header and the size of the
 303         * payload
 304         */
 305        headersz  = sizeof(struct main_hdr_v0);
 306
 307        if (image_count_options(IMAGE_CFG_DATA) > 0) {
 308                has_ext = 1;
 309                headersz += sizeof(struct ext_hdr_v0);
 310        }
 311
 312        if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
 313                fprintf(stderr, "More than one payload, not possible\n");
 314                return NULL;
 315        }
 316
 317        image = malloc(headersz);
 318        if (!image) {
 319                fprintf(stderr, "Cannot allocate memory for image\n");
 320                return NULL;
 321        }
 322
 323        memset(image, 0, headersz);
 324
 325        main_hdr = image;
 326
 327        /* Fill in the main header */
 328        main_hdr->blocksize = payloadsz + sizeof(uint32_t) - headersz;
 329        main_hdr->srcaddr   = headersz;
 330        main_hdr->ext       = has_ext;
 331        main_hdr->destaddr  = params->addr;
 332        main_hdr->execaddr  = params->ep;
 333
 334        e = image_find_option(IMAGE_CFG_BOOT_FROM);
 335        if (e)
 336                main_hdr->blockid = e->bootfrom;
 337        e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
 338        if (e)
 339                main_hdr->nandeccmode = e->nandeccmode;
 340        e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
 341        if (e)
 342                main_hdr->nandpagesize = e->nandpagesz;
 343        main_hdr->checksum = image_checksum8(image,
 344                                             sizeof(struct main_hdr_v0));
 345
 346        /* Generate the ext header */
 347        if (has_ext) {
 348                int cfgi, datai;
 349
 350                ext_hdr = image + sizeof(struct main_hdr_v0);
 351                ext_hdr->offset = 0x40;
 352
 353                for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
 354                        e = &image_cfg[cfgi];
 355                        if (e->type != IMAGE_CFG_DATA)
 356                                continue;
 357
 358                        ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
 359                        ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
 360                        datai++;
 361                }
 362
 363                ext_hdr->checksum = image_checksum8(ext_hdr,
 364                                                    sizeof(struct ext_hdr_v0));
 365        }
 366
 367        *imagesz = headersz;
 368        return image;
 369}
 370
 371static size_t image_headersz_v1(struct image_tool_params *params,
 372                                int *hasext)
 373{
 374        struct image_cfg_element *binarye;
 375        size_t headersz;
 376        int ret;
 377
 378        /*
 379         * Calculate the size of the header and the size of the
 380         * payload
 381         */
 382        headersz = sizeof(struct main_hdr_v1);
 383
 384        if (image_count_options(IMAGE_CFG_BINARY) > 1) {
 385                fprintf(stderr, "More than one binary blob, not supported\n");
 386                return 0;
 387        }
 388
 389        if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
 390                fprintf(stderr, "More than one payload, not possible\n");
 391                return 0;
 392        }
 393
 394        binarye = image_find_option(IMAGE_CFG_BINARY);
 395        if (binarye) {
 396                struct stat s;
 397
 398                ret = stat(binarye->binary.file, &s);
 399                if (ret < 0) {
 400                        char cwd[PATH_MAX];
 401                        char *dir = cwd;
 402
 403                        memset(cwd, 0, sizeof(cwd));
 404                        if (!getcwd(cwd, sizeof(cwd))) {
 405                                dir = "current working directory";
 406                                perror("getcwd() failed");
 407                        }
 408
 409                        fprintf(stderr,
 410                                "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
 411                                "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
 412                                "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
 413                                binarye->binary.file, dir);
 414                        return 0;
 415                }
 416
 417                headersz += s.st_size +
 418                        binarye->binary.nargs * sizeof(unsigned int);
 419                if (hasext)
 420                        *hasext = 1;
 421        }
 422
 423#if defined(CONFIG_SYS_SPI_U_BOOT_OFFS)
 424        if (headersz > CONFIG_SYS_SPI_U_BOOT_OFFS) {
 425                fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
 426                fprintf(stderr, "header=0x%x CONFIG_SYS_SPI_U_BOOT_OFFS=0x%x!\n",
 427                        (int)headersz, CONFIG_SYS_SPI_U_BOOT_OFFS);
 428                fprintf(stderr, "Increase CONFIG_SYS_SPI_U_BOOT_OFFS!\n");
 429                return 0;
 430        } else {
 431                headersz = CONFIG_SYS_SPI_U_BOOT_OFFS;
 432        }
 433#endif
 434
 435        /*
 436         * The payload should be aligned on some reasonable
 437         * boundary
 438         */
 439        return ALIGN_SUP(headersz, 4096);
 440}
 441
 442static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
 443                             int payloadsz)
 444{
 445        struct image_cfg_element *e, *binarye;
 446        struct main_hdr_v1 *main_hdr;
 447        size_t headersz;
 448        void *image, *cur;
 449        int hasext = 0;
 450        int ret;
 451
 452        /*
 453         * Calculate the size of the header and the size of the
 454         * payload
 455         */
 456        headersz = image_headersz_v1(params, &hasext);
 457        if (headersz == 0)
 458                return NULL;
 459
 460        image = malloc(headersz);
 461        if (!image) {
 462                fprintf(stderr, "Cannot allocate memory for image\n");
 463                return NULL;
 464        }
 465
 466        memset(image, 0, headersz);
 467
 468        cur = main_hdr = image;
 469        cur += sizeof(struct main_hdr_v1);
 470
 471        /* Fill the main header */
 472        main_hdr->blocksize    = payloadsz - headersz + sizeof(uint32_t);
 473        main_hdr->headersz_lsb = headersz & 0xFFFF;
 474        main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
 475        main_hdr->destaddr     = params->addr;
 476        main_hdr->execaddr     = params->ep;
 477        main_hdr->srcaddr      = headersz;
 478        main_hdr->ext          = hasext;
 479        main_hdr->version      = 1;
 480        e = image_find_option(IMAGE_CFG_BOOT_FROM);
 481        if (e)
 482                main_hdr->blockid = e->bootfrom;
 483        e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
 484        if (e)
 485                main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
 486        e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
 487        if (e)
 488                main_hdr->nandbadblklocation = e->nandbadblklocation;
 489
 490        binarye = image_find_option(IMAGE_CFG_BINARY);
 491        if (binarye) {
 492                struct opt_hdr_v1 *hdr = cur;
 493                unsigned int *args;
 494                size_t binhdrsz;
 495                struct stat s;
 496                int argi;
 497                FILE *bin;
 498
 499                hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
 500
 501                bin = fopen(binarye->binary.file, "r");
 502                if (!bin) {
 503                        fprintf(stderr, "Cannot open binary file %s\n",
 504                                binarye->binary.file);
 505                        return NULL;
 506                }
 507
 508                fstat(fileno(bin), &s);
 509
 510                binhdrsz = sizeof(struct opt_hdr_v1) +
 511                        (binarye->binary.nargs + 1) * sizeof(unsigned int) +
 512                        s.st_size;
 513                binhdrsz = ALIGN_SUP(binhdrsz, 32);
 514                hdr->headersz_lsb = binhdrsz & 0xFFFF;
 515                hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
 516
 517                cur += sizeof(struct opt_hdr_v1);
 518
 519                args = cur;
 520                *args = binarye->binary.nargs;
 521                args++;
 522                for (argi = 0; argi < binarye->binary.nargs; argi++)
 523                        args[argi] = binarye->binary.args[argi];
 524
 525                cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
 526
 527                ret = fread(cur, s.st_size, 1, bin);
 528                if (ret != 1) {
 529                        fprintf(stderr,
 530                                "Could not read binary image %s\n",
 531                                binarye->binary.file);
 532                        return NULL;
 533                }
 534
 535                fclose(bin);
 536
 537                cur += s.st_size;
 538
 539                /*
 540                 * For now, we don't support more than one binary
 541                 * header, and no other header types are
 542                 * supported. So, the binary header is necessarily the
 543                 * last one
 544                 */
 545                *((unsigned char *)cur) = 0;
 546
 547                cur += sizeof(uint32_t);
 548        }
 549
 550        /* Calculate and set the header checksum */
 551        main_hdr->checksum = image_checksum8(main_hdr, headersz);
 552
 553        *imagesz = headersz;
 554        return image;
 555}
 556
 557static int image_create_config_parse_oneline(char *line,
 558                                             struct image_cfg_element *el)
 559{
 560        char *keyword, *saveptr;
 561        char deliminiters[] = " \t";
 562
 563        keyword = strtok_r(line, deliminiters, &saveptr);
 564        if (!strcmp(keyword, "VERSION")) {
 565                char *value = strtok_r(NULL, deliminiters, &saveptr);
 566                el->type = IMAGE_CFG_VERSION;
 567                el->version = atoi(value);
 568        } else if (!strcmp(keyword, "BOOT_FROM")) {
 569                char *value = strtok_r(NULL, deliminiters, &saveptr);
 570                int ret = image_boot_mode_id(value);
 571                if (ret < 0) {
 572                        fprintf(stderr,
 573                                "Invalid boot media '%s'\n", value);
 574                        return -1;
 575                }
 576                el->type = IMAGE_CFG_BOOT_FROM;
 577                el->bootfrom = ret;
 578        } else if (!strcmp(keyword, "NAND_BLKSZ")) {
 579                char *value = strtok_r(NULL, deliminiters, &saveptr);
 580                el->type = IMAGE_CFG_NAND_BLKSZ;
 581                el->nandblksz = strtoul(value, NULL, 16);
 582        } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
 583                char *value = strtok_r(NULL, deliminiters, &saveptr);
 584                el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
 585                el->nandbadblklocation =
 586                        strtoul(value, NULL, 16);
 587        } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
 588                char *value = strtok_r(NULL, deliminiters, &saveptr);
 589                int ret = image_nand_ecc_mode_id(value);
 590                if (ret < 0) {
 591                        fprintf(stderr,
 592                                "Invalid NAND ECC mode '%s'\n", value);
 593                        return -1;
 594                }
 595                el->type = IMAGE_CFG_NAND_ECC_MODE;
 596                el->nandeccmode = ret;
 597        } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
 598                char *value = strtok_r(NULL, deliminiters, &saveptr);
 599                el->type = IMAGE_CFG_NAND_PAGESZ;
 600                el->nandpagesz = strtoul(value, NULL, 16);
 601        } else if (!strcmp(keyword, "BINARY")) {
 602                char *value = strtok_r(NULL, deliminiters, &saveptr);
 603                int argi = 0;
 604
 605                el->type = IMAGE_CFG_BINARY;
 606                el->binary.file = strdup(value);
 607                while (1) {
 608                        value = strtok_r(NULL, deliminiters, &saveptr);
 609                        if (!value)
 610                                break;
 611                        el->binary.args[argi] = strtoul(value, NULL, 16);
 612                        argi++;
 613                        if (argi >= BINARY_MAX_ARGS) {
 614                                fprintf(stderr,
 615                                        "Too many argument for binary\n");
 616                                return -1;
 617                        }
 618                }
 619                el->binary.nargs = argi;
 620        } else if (!strcmp(keyword, "DATA")) {
 621                char *value1 = strtok_r(NULL, deliminiters, &saveptr);
 622                char *value2 = strtok_r(NULL, deliminiters, &saveptr);
 623
 624                if (!value1 || !value2) {
 625                        fprintf(stderr,
 626                                "Invalid number of arguments for DATA\n");
 627                        return -1;
 628                }
 629
 630                el->type = IMAGE_CFG_DATA;
 631                el->regdata.raddr = strtoul(value1, NULL, 16);
 632                el->regdata.rdata = strtoul(value2, NULL, 16);
 633        } else {
 634                fprintf(stderr, "Ignoring unknown line '%s'\n", line);
 635        }
 636
 637        return 0;
 638}
 639
 640/*
 641 * Parse the configuration file 'fcfg' into the array of configuration
 642 * elements 'image_cfg', and return the number of configuration
 643 * elements in 'cfgn'.
 644 */
 645static int image_create_config_parse(FILE *fcfg)
 646{
 647        int ret;
 648        int cfgi = 0;
 649
 650        /* Parse the configuration file */
 651        while (!feof(fcfg)) {
 652                char *line;
 653                char buf[256];
 654
 655                /* Read the current line */
 656                memset(buf, 0, sizeof(buf));
 657                line = fgets(buf, sizeof(buf), fcfg);
 658                if (!line)
 659                        break;
 660
 661                /* Ignore useless lines */
 662                if (line[0] == '\n' || line[0] == '#')
 663                        continue;
 664
 665                /* Strip final newline */
 666                if (line[strlen(line) - 1] == '\n')
 667                        line[strlen(line) - 1] = 0;
 668
 669                /* Parse the current line */
 670                ret = image_create_config_parse_oneline(line,
 671                                                        &image_cfg[cfgi]);
 672                if (ret)
 673                        return ret;
 674
 675                cfgi++;
 676
 677                if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
 678                        fprintf(stderr,
 679                                "Too many configuration elements in .cfg file\n");
 680                        return -1;
 681                }
 682        }
 683
 684        cfgn = cfgi;
 685        return 0;
 686}
 687
 688static int image_get_version(void)
 689{
 690        struct image_cfg_element *e;
 691
 692        e = image_find_option(IMAGE_CFG_VERSION);
 693        if (!e)
 694                return -1;
 695
 696        return e->version;
 697}
 698
 699static int image_version_file(const char *input)
 700{
 701        FILE *fcfg;
 702        int version;
 703        int ret;
 704
 705        fcfg = fopen(input, "r");
 706        if (!fcfg) {
 707                fprintf(stderr, "Could not open input file %s\n", input);
 708                return -1;
 709        }
 710
 711        image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
 712                           sizeof(struct image_cfg_element));
 713        if (!image_cfg) {
 714                fprintf(stderr, "Cannot allocate memory\n");
 715                fclose(fcfg);
 716                return -1;
 717        }
 718
 719        memset(image_cfg, 0,
 720               IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
 721        rewind(fcfg);
 722
 723        ret = image_create_config_parse(fcfg);
 724        fclose(fcfg);
 725        if (ret) {
 726                free(image_cfg);
 727                return -1;
 728        }
 729
 730        version = image_get_version();
 731        /* Fallback to version 0 is no version is provided in the cfg file */
 732        if (version == -1)
 733                version = 0;
 734
 735        free(image_cfg);
 736
 737        return version;
 738}
 739
 740static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
 741                                struct image_tool_params *params)
 742{
 743        FILE *fcfg;
 744        void *image = NULL;
 745        int version;
 746        size_t headersz = 0;
 747        uint32_t checksum;
 748        int ret;
 749        int size;
 750
 751        fcfg = fopen(params->imagename, "r");
 752        if (!fcfg) {
 753                fprintf(stderr, "Could not open input file %s\n",
 754                        params->imagename);
 755                exit(EXIT_FAILURE);
 756        }
 757
 758        image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
 759                           sizeof(struct image_cfg_element));
 760        if (!image_cfg) {
 761                fprintf(stderr, "Cannot allocate memory\n");
 762                fclose(fcfg);
 763                exit(EXIT_FAILURE);
 764        }
 765
 766        memset(image_cfg, 0,
 767               IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
 768        rewind(fcfg);
 769
 770        ret = image_create_config_parse(fcfg);
 771        fclose(fcfg);
 772        if (ret) {
 773                free(image_cfg);
 774                exit(EXIT_FAILURE);
 775        }
 776
 777        version = image_get_version();
 778        switch (version) {
 779                /*
 780                 * Fallback to version 0 if no version is provided in the
 781                 * cfg file
 782                 */
 783        case -1:
 784        case 0:
 785                image = image_create_v0(&headersz, params, sbuf->st_size);
 786                break;
 787
 788        case 1:
 789                image = image_create_v1(&headersz, params, sbuf->st_size);
 790                break;
 791
 792        default:
 793                fprintf(stderr, "Unsupported version %d\n", version);
 794                free(image_cfg);
 795                exit(EXIT_FAILURE);
 796        }
 797
 798        if (!image) {
 799                fprintf(stderr, "Could not create image\n");
 800                free(image_cfg);
 801                exit(EXIT_FAILURE);
 802        }
 803
 804        free(image_cfg);
 805
 806        /* Build and add image checksum header */
 807        checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
 808        size = write(ifd, &checksum, sizeof(uint32_t));
 809        if (size != sizeof(uint32_t)) {
 810                fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
 811                        params->cmdname, size, params->imagefile);
 812                exit(EXIT_FAILURE);
 813        }
 814
 815        sbuf->st_size += sizeof(uint32_t);
 816
 817        /* Finally copy the header into the image area */
 818        memcpy(ptr, image, headersz);
 819
 820        free(image);
 821}
 822
 823static void kwbimage_print_header(const void *ptr)
 824{
 825        struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
 826
 827        printf("Image Type:   MVEBU Boot from %s Image\n",
 828               image_boot_mode_name(mhdr->blockid));
 829        printf("Image version:%d\n", image_version((void *)ptr));
 830        printf("Data Size:    ");
 831        genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
 832        printf("Load Address: %08x\n", mhdr->destaddr);
 833        printf("Entry Point:  %08x\n", mhdr->execaddr);
 834}
 835
 836static int kwbimage_check_image_types(uint8_t type)
 837{
 838        if (type == IH_TYPE_KWBIMAGE)
 839                return EXIT_SUCCESS;
 840        else
 841                return EXIT_FAILURE;
 842}
 843
 844static int kwbimage_verify_header(unsigned char *ptr, int image_size,
 845                                  struct image_tool_params *params)
 846{
 847        struct main_hdr_v0 *main_hdr;
 848        struct ext_hdr_v0 *ext_hdr;
 849        uint8_t checksum;
 850
 851        main_hdr = (void *)ptr;
 852        checksum = image_checksum8(ptr,
 853                                   sizeof(struct main_hdr_v0)
 854                                   - sizeof(uint8_t));
 855        if (checksum != main_hdr->checksum)
 856                return -FDT_ERR_BADSTRUCTURE;
 857
 858        /* Only version 0 extended header has checksum */
 859        if (image_version((void *)ptr) == 0) {
 860                ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
 861                checksum = image_checksum8(ext_hdr,
 862                                           sizeof(struct ext_hdr_v0)
 863                                           - sizeof(uint8_t));
 864                if (checksum != ext_hdr->checksum)
 865                        return -FDT_ERR_BADSTRUCTURE;
 866        }
 867
 868        return 0;
 869}
 870
 871static int kwbimage_generate(struct image_tool_params *params,
 872                             struct image_type_params *tparams)
 873{
 874        int alloc_len;
 875        void *hdr;
 876        int version = 0;
 877
 878        version = image_version_file(params->imagename);
 879        if (version == 0) {
 880                alloc_len = sizeof(struct main_hdr_v0) +
 881                        sizeof(struct ext_hdr_v0);
 882        } else {
 883                alloc_len = image_headersz_v1(params, NULL);
 884        }
 885
 886        hdr = malloc(alloc_len);
 887        if (!hdr) {
 888                fprintf(stderr, "%s: malloc return failure: %s\n",
 889                        params->cmdname, strerror(errno));
 890                exit(EXIT_FAILURE);
 891        }
 892
 893        memset(hdr, 0, alloc_len);
 894        tparams->header_size = alloc_len;
 895        tparams->hdr = hdr;
 896
 897        return 0;
 898}
 899
 900/*
 901 * Report Error if xflag is set in addition to default
 902 */
 903static int kwbimage_check_params(struct image_tool_params *params)
 904{
 905        if (!strlen(params->imagename)) {
 906                fprintf(stderr, "Error:%s - Configuration file not specified, "
 907                        "it is needed for kwbimage generation\n",
 908                        params->cmdname);
 909                return CFG_INVALID;
 910        }
 911
 912        return (params->dflag && (params->fflag || params->lflag)) ||
 913                (params->fflag && (params->dflag || params->lflag)) ||
 914                (params->lflag && (params->dflag || params->fflag)) ||
 915                (params->xflag) || !(strlen(params->imagename));
 916}
 917
 918/*
 919 * kwbimage type parameters definition
 920 */
 921U_BOOT_IMAGE_TYPE(
 922        kwbimage,
 923        "Marvell MVEBU Boot Image support",
 924        0,
 925        NULL,
 926        kwbimage_check_params,
 927        kwbimage_verify_header,
 928        kwbimage_print_header,
 929        kwbimage_set_header,
 930        NULL,
 931        kwbimage_check_image_types,
 932        NULL,
 933        kwbimage_generate
 934);
 935