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 static struct image_cfg_element *image_cfg; 21 static int cfgn; 22 23 struct boot_mode { 24 unsigned int id; 25 const char *name; 26 }; 27 28 struct 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 39 struct nand_ecc_mode { 40 unsigned int id; 41 const char *name; 42 }; 43 44 struct 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 */ 58 struct 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 99 static 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 108 int 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 118 int 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 127 static struct image_cfg_element * 128 image_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 140 static unsigned int 141 image_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 */ 157 static 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 174 static 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 198 static 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 281 static 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 353 static 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 475 static 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 */ 563 static 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 606 static 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 617 static 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 658 static 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 745 static 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 758 static 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 766 static 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 793 static 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 */ 833 static 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 */ 851 U_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