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