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) */ 23 struct 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 40 struct 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 47 struct 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) */ 56 struct 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 */ 79 struct 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 103 static struct image_cfg_element *image_cfg; 104 static int cfgn; 105 106 struct boot_mode { 107 unsigned int id; 108 const char *name; 109 }; 110 111 struct 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 121 struct nand_ecc_mode { 122 unsigned int id; 123 const char *name; 124 }; 125 126 struct 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 */ 140 struct 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 */ 180 static 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 192 static 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 201 int 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 211 int 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 220 static struct image_cfg_element * 221 image_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 233 static unsigned int 234 image_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 */ 250 static 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 267 static 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 291 static 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 371 static 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 /* 424 * The payload should be aligned on some reasonable 425 * boundary 426 */ 427 return ALIGN_SUP(headersz, 4096); 428 } 429 430 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, 431 int payloadsz) 432 { 433 struct image_cfg_element *e, *binarye; 434 struct main_hdr_v1 *main_hdr; 435 size_t headersz; 436 void *image, *cur; 437 int hasext = 0; 438 int ret; 439 440 /* 441 * Calculate the size of the header and the size of the 442 * payload 443 */ 444 headersz = image_headersz_v1(params, &hasext); 445 if (headersz == 0) 446 return NULL; 447 448 image = malloc(headersz); 449 if (!image) { 450 fprintf(stderr, "Cannot allocate memory for image\n"); 451 return NULL; 452 } 453 454 memset(image, 0, headersz); 455 456 cur = main_hdr = image; 457 cur += sizeof(struct main_hdr_v1); 458 459 /* Fill the main header */ 460 main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t); 461 main_hdr->headersz_lsb = headersz & 0xFFFF; 462 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16; 463 main_hdr->destaddr = params->addr; 464 main_hdr->execaddr = params->ep; 465 main_hdr->srcaddr = headersz; 466 main_hdr->ext = hasext; 467 main_hdr->version = 1; 468 e = image_find_option(IMAGE_CFG_BOOT_FROM); 469 if (e) 470 main_hdr->blockid = e->bootfrom; 471 e = image_find_option(IMAGE_CFG_NAND_BLKSZ); 472 if (e) 473 main_hdr->nandblocksize = e->nandblksz / (64 * 1024); 474 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION); 475 if (e) 476 main_hdr->nandbadblklocation = e->nandbadblklocation; 477 478 binarye = image_find_option(IMAGE_CFG_BINARY); 479 if (binarye) { 480 struct opt_hdr_v1 *hdr = cur; 481 unsigned int *args; 482 size_t binhdrsz; 483 struct stat s; 484 int argi; 485 FILE *bin; 486 487 hdr->headertype = OPT_HDR_V1_BINARY_TYPE; 488 489 bin = fopen(binarye->binary.file, "r"); 490 if (!bin) { 491 fprintf(stderr, "Cannot open binary file %s\n", 492 binarye->binary.file); 493 return NULL; 494 } 495 496 fstat(fileno(bin), &s); 497 498 binhdrsz = sizeof(struct opt_hdr_v1) + 499 (binarye->binary.nargs + 1) * sizeof(unsigned int) + 500 s.st_size; 501 hdr->headersz_lsb = binhdrsz & 0xFFFF; 502 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; 503 504 cur += sizeof(struct opt_hdr_v1); 505 506 args = cur; 507 *args = binarye->binary.nargs; 508 args++; 509 for (argi = 0; argi < binarye->binary.nargs; argi++) 510 args[argi] = binarye->binary.args[argi]; 511 512 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int); 513 514 ret = fread(cur, s.st_size, 1, bin); 515 if (ret != 1) { 516 fprintf(stderr, 517 "Could not read binary image %s\n", 518 binarye->binary.file); 519 return NULL; 520 } 521 522 fclose(bin); 523 524 cur += s.st_size; 525 526 /* 527 * For now, we don't support more than one binary 528 * header, and no other header types are 529 * supported. So, the binary header is necessarily the 530 * last one 531 */ 532 *((unsigned char *)cur) = 0; 533 534 cur += sizeof(uint32_t); 535 } 536 537 /* Calculate and set the header checksum */ 538 main_hdr->checksum = image_checksum8(main_hdr, headersz); 539 540 *imagesz = headersz; 541 return image; 542 } 543 544 static int image_create_config_parse_oneline(char *line, 545 struct image_cfg_element *el) 546 { 547 char *keyword, *saveptr; 548 char deliminiters[] = " \t"; 549 550 keyword = strtok_r(line, deliminiters, &saveptr); 551 if (!strcmp(keyword, "VERSION")) { 552 char *value = strtok_r(NULL, deliminiters, &saveptr); 553 el->type = IMAGE_CFG_VERSION; 554 el->version = atoi(value); 555 } else if (!strcmp(keyword, "BOOT_FROM")) { 556 char *value = strtok_r(NULL, deliminiters, &saveptr); 557 int ret = image_boot_mode_id(value); 558 if (ret < 0) { 559 fprintf(stderr, 560 "Invalid boot media '%s'\n", value); 561 return -1; 562 } 563 el->type = IMAGE_CFG_BOOT_FROM; 564 el->bootfrom = ret; 565 } else if (!strcmp(keyword, "NAND_BLKSZ")) { 566 char *value = strtok_r(NULL, deliminiters, &saveptr); 567 el->type = IMAGE_CFG_NAND_BLKSZ; 568 el->nandblksz = strtoul(value, NULL, 16); 569 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) { 570 char *value = strtok_r(NULL, deliminiters, &saveptr); 571 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION; 572 el->nandbadblklocation = 573 strtoul(value, NULL, 16); 574 } else if (!strcmp(keyword, "NAND_ECC_MODE")) { 575 char *value = strtok_r(NULL, deliminiters, &saveptr); 576 int ret = image_nand_ecc_mode_id(value); 577 if (ret < 0) { 578 fprintf(stderr, 579 "Invalid NAND ECC mode '%s'\n", value); 580 return -1; 581 } 582 el->type = IMAGE_CFG_NAND_ECC_MODE; 583 el->nandeccmode = ret; 584 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) { 585 char *value = strtok_r(NULL, deliminiters, &saveptr); 586 el->type = IMAGE_CFG_NAND_PAGESZ; 587 el->nandpagesz = strtoul(value, NULL, 16); 588 } else if (!strcmp(keyword, "BINARY")) { 589 char *value = strtok_r(NULL, deliminiters, &saveptr); 590 int argi = 0; 591 592 el->type = IMAGE_CFG_BINARY; 593 el->binary.file = strdup(value); 594 while (1) { 595 value = strtok_r(NULL, deliminiters, &saveptr); 596 if (!value) 597 break; 598 el->binary.args[argi] = strtoul(value, NULL, 16); 599 argi++; 600 if (argi >= BINARY_MAX_ARGS) { 601 fprintf(stderr, 602 "Too many argument for binary\n"); 603 return -1; 604 } 605 } 606 el->binary.nargs = argi; 607 } else if (!strcmp(keyword, "DATA")) { 608 char *value1 = strtok_r(NULL, deliminiters, &saveptr); 609 char *value2 = strtok_r(NULL, deliminiters, &saveptr); 610 611 if (!value1 || !value2) { 612 fprintf(stderr, 613 "Invalid number of arguments for DATA\n"); 614 return -1; 615 } 616 617 el->type = IMAGE_CFG_DATA; 618 el->regdata.raddr = strtoul(value1, NULL, 16); 619 el->regdata.rdata = strtoul(value2, NULL, 16); 620 } else { 621 fprintf(stderr, "Ignoring unknown line '%s'\n", line); 622 } 623 624 return 0; 625 } 626 627 /* 628 * Parse the configuration file 'fcfg' into the array of configuration 629 * elements 'image_cfg', and return the number of configuration 630 * elements in 'cfgn'. 631 */ 632 static int image_create_config_parse(FILE *fcfg) 633 { 634 int ret; 635 int cfgi = 0; 636 637 /* Parse the configuration file */ 638 while (!feof(fcfg)) { 639 char *line; 640 char buf[256]; 641 642 /* Read the current line */ 643 memset(buf, 0, sizeof(buf)); 644 line = fgets(buf, sizeof(buf), fcfg); 645 if (!line) 646 break; 647 648 /* Ignore useless lines */ 649 if (line[0] == '\n' || line[0] == '#') 650 continue; 651 652 /* Strip final newline */ 653 if (line[strlen(line) - 1] == '\n') 654 line[strlen(line) - 1] = 0; 655 656 /* Parse the current line */ 657 ret = image_create_config_parse_oneline(line, 658 &image_cfg[cfgi]); 659 if (ret) 660 return ret; 661 662 cfgi++; 663 664 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) { 665 fprintf(stderr, 666 "Too many configuration elements in .cfg file\n"); 667 return -1; 668 } 669 } 670 671 cfgn = cfgi; 672 return 0; 673 } 674 675 static int image_get_version(void) 676 { 677 struct image_cfg_element *e; 678 679 e = image_find_option(IMAGE_CFG_VERSION); 680 if (!e) 681 return -1; 682 683 return e->version; 684 } 685 686 static int image_version_file(const char *input) 687 { 688 FILE *fcfg; 689 int version; 690 int ret; 691 692 fcfg = fopen(input, "r"); 693 if (!fcfg) { 694 fprintf(stderr, "Could not open input file %s\n", input); 695 return -1; 696 } 697 698 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX * 699 sizeof(struct image_cfg_element)); 700 if (!image_cfg) { 701 fprintf(stderr, "Cannot allocate memory\n"); 702 fclose(fcfg); 703 return -1; 704 } 705 706 memset(image_cfg, 0, 707 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element)); 708 rewind(fcfg); 709 710 ret = image_create_config_parse(fcfg); 711 fclose(fcfg); 712 if (ret) { 713 free(image_cfg); 714 return -1; 715 } 716 717 version = image_get_version(); 718 /* Fallback to version 0 is no version is provided in the cfg file */ 719 if (version == -1) 720 version = 0; 721 722 free(image_cfg); 723 724 return version; 725 } 726 727 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd, 728 struct image_tool_params *params) 729 { 730 FILE *fcfg; 731 void *image = NULL; 732 int version; 733 size_t headersz = 0; 734 uint32_t checksum; 735 int ret; 736 int size; 737 738 fcfg = fopen(params->imagename, "r"); 739 if (!fcfg) { 740 fprintf(stderr, "Could not open input file %s\n", 741 params->imagename); 742 exit(EXIT_FAILURE); 743 } 744 745 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX * 746 sizeof(struct image_cfg_element)); 747 if (!image_cfg) { 748 fprintf(stderr, "Cannot allocate memory\n"); 749 fclose(fcfg); 750 exit(EXIT_FAILURE); 751 } 752 753 memset(image_cfg, 0, 754 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element)); 755 rewind(fcfg); 756 757 ret = image_create_config_parse(fcfg); 758 fclose(fcfg); 759 if (ret) { 760 free(image_cfg); 761 exit(EXIT_FAILURE); 762 } 763 764 version = image_get_version(); 765 switch (version) { 766 /* 767 * Fallback to version 0 if no version is provided in the 768 * cfg file 769 */ 770 case -1: 771 case 0: 772 image = image_create_v0(&headersz, params, sbuf->st_size); 773 break; 774 775 case 1: 776 image = image_create_v1(&headersz, params, sbuf->st_size); 777 break; 778 779 default: 780 fprintf(stderr, "Unsupported version %d\n", version); 781 free(image_cfg); 782 exit(EXIT_FAILURE); 783 } 784 785 if (!image) { 786 fprintf(stderr, "Could not create image\n"); 787 free(image_cfg); 788 exit(EXIT_FAILURE); 789 } 790 791 free(image_cfg); 792 793 /* Build and add image checksum header */ 794 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size); 795 size = write(ifd, &checksum, sizeof(uint32_t)); 796 if (size != sizeof(uint32_t)) { 797 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n", 798 params->cmdname, size, params->imagefile); 799 exit(EXIT_FAILURE); 800 } 801 802 sbuf->st_size += sizeof(uint32_t); 803 804 /* Finally copy the header into the image area */ 805 memcpy(ptr, image, headersz); 806 807 free(image); 808 } 809 810 static void kwbimage_print_header(const void *ptr) 811 { 812 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr; 813 814 printf("Image Type: MVEBU Boot from %s Image\n", 815 image_boot_mode_name(mhdr->blockid)); 816 printf("Image version:%d\n", image_version((void *)ptr)); 817 printf("Data Size: "); 818 genimg_print_size(mhdr->blocksize - sizeof(uint32_t)); 819 printf("Load Address: %08x\n", mhdr->destaddr); 820 printf("Entry Point: %08x\n", mhdr->execaddr); 821 } 822 823 static int kwbimage_check_image_types(uint8_t type) 824 { 825 if (type == IH_TYPE_KWBIMAGE) 826 return EXIT_SUCCESS; 827 else 828 return EXIT_FAILURE; 829 } 830 831 static int kwbimage_verify_header(unsigned char *ptr, int image_size, 832 struct image_tool_params *params) 833 { 834 struct main_hdr_v0 *main_hdr; 835 struct ext_hdr_v0 *ext_hdr; 836 uint8_t checksum; 837 838 main_hdr = (void *)ptr; 839 checksum = image_checksum8(ptr, 840 sizeof(struct main_hdr_v0) 841 - sizeof(uint8_t)); 842 if (checksum != main_hdr->checksum) 843 return -FDT_ERR_BADSTRUCTURE; 844 845 /* Only version 0 extended header has checksum */ 846 if (image_version((void *)ptr) == 0) { 847 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0); 848 checksum = image_checksum8(ext_hdr, 849 sizeof(struct ext_hdr_v0) 850 - sizeof(uint8_t)); 851 if (checksum != ext_hdr->checksum) 852 return -FDT_ERR_BADSTRUCTURE; 853 } 854 855 return 0; 856 } 857 858 static int kwbimage_generate(struct image_tool_params *params, 859 struct image_type_params *tparams) 860 { 861 int alloc_len; 862 void *hdr; 863 int version = 0; 864 865 version = image_version_file(params->imagename); 866 if (version == 0) { 867 alloc_len = sizeof(struct main_hdr_v0) + 868 sizeof(struct ext_hdr_v0); 869 } else { 870 alloc_len = image_headersz_v1(params, NULL); 871 } 872 873 hdr = malloc(alloc_len); 874 if (!hdr) { 875 fprintf(stderr, "%s: malloc return failure: %s\n", 876 params->cmdname, strerror(errno)); 877 exit(EXIT_FAILURE); 878 } 879 880 memset(hdr, 0, alloc_len); 881 tparams->header_size = alloc_len; 882 tparams->hdr = hdr; 883 884 return 0; 885 } 886 887 /* 888 * Report Error if xflag is set in addition to default 889 */ 890 static int kwbimage_check_params(struct image_tool_params *params) 891 { 892 if (!strlen(params->imagename)) { 893 fprintf(stderr, "Error:%s - Configuration file not specified, " 894 "it is needed for kwbimage generation\n", 895 params->cmdname); 896 return CFG_INVALID; 897 } 898 899 return (params->dflag && (params->fflag || params->lflag)) || 900 (params->fflag && (params->dflag || params->lflag)) || 901 (params->lflag && (params->dflag || params->fflag)) || 902 (params->xflag) || !(strlen(params->imagename)); 903 } 904 905 /* 906 * kwbimage type parameters definition 907 */ 908 static struct image_type_params kwbimage_params = { 909 .name = "Marvell MVEBU Boot Image support", 910 .header_size = 0, /* no fixed header size */ 911 .hdr = NULL, 912 .vrec_header = kwbimage_generate, 913 .check_image_type = kwbimage_check_image_types, 914 .verify_header = kwbimage_verify_header, 915 .print_header = kwbimage_print_header, 916 .set_header = kwbimage_set_header, 917 .check_params = kwbimage_check_params, 918 }; 919 920 void init_kwb_image_type (void) 921 { 922 register_image_type(&kwbimage_params); 923 } 924