1 /* 2 * (C) Copyright 2009 3 * Stefano Babic, DENX Software Engineering, sbabic@denx.de. 4 * 5 * (C) Copyright 2008 6 * Marvell Semiconductor <www.marvell.com> 7 * Written-by: Prafulla Wadaskar <prafulla@marvell.com> 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include "imagetool.h" 13 #include <image.h> 14 #include "imximage.h" 15 16 #define UNDEFINED 0xFFFFFFFF 17 18 /* 19 * Supported commands for configuration file 20 */ 21 static table_entry_t imximage_cmds[] = { 22 {CMD_BOOT_FROM, "BOOT_FROM", "boot command", }, 23 {CMD_BOOT_OFFSET, "BOOT_OFFSET", "Boot offset", }, 24 {CMD_WRITE_DATA, "DATA", "Reg Write Data", }, 25 {CMD_WRITE_CLR_BIT, "CLR_BIT", "Reg clear bit", }, 26 {CMD_CHECK_BITS_SET, "CHECK_BITS_SET", "Reg Check bits set", }, 27 {CMD_CHECK_BITS_CLR, "CHECK_BITS_CLR", "Reg Check bits clr", }, 28 {CMD_CSF, "CSF", "Command Sequence File", }, 29 {CMD_IMAGE_VERSION, "IMAGE_VERSION", "image version", }, 30 {-1, "", "", }, 31 }; 32 33 /* 34 * Supported Boot options for configuration file 35 * this is needed to set the correct flash offset 36 */ 37 static table_entry_t imximage_boot_offset[] = { 38 {FLASH_OFFSET_ONENAND, "onenand", "OneNAND Flash",}, 39 {FLASH_OFFSET_NAND, "nand", "NAND Flash", }, 40 {FLASH_OFFSET_NOR, "nor", "NOR Flash", }, 41 {FLASH_OFFSET_SATA, "sata", "SATA Disk", }, 42 {FLASH_OFFSET_SD, "sd", "SD Card", }, 43 {FLASH_OFFSET_SPI, "spi", "SPI Flash", }, 44 {FLASH_OFFSET_QSPI, "qspi", "QSPI NOR Flash",}, 45 {-1, "", "Invalid", }, 46 }; 47 48 /* 49 * Supported Boot options for configuration file 50 * this is needed to determine the initial load size 51 */ 52 static table_entry_t imximage_boot_loadsize[] = { 53 {FLASH_LOADSIZE_ONENAND, "onenand", "OneNAND Flash",}, 54 {FLASH_LOADSIZE_NAND, "nand", "NAND Flash", }, 55 {FLASH_LOADSIZE_NOR, "nor", "NOR Flash", }, 56 {FLASH_LOADSIZE_SATA, "sata", "SATA Disk", }, 57 {FLASH_LOADSIZE_SD, "sd", "SD Card", }, 58 {FLASH_LOADSIZE_SPI, "spi", "SPI Flash", }, 59 {FLASH_LOADSIZE_QSPI, "qspi", "QSPI NOR Flash",}, 60 {-1, "", "Invalid", }, 61 }; 62 63 /* 64 * IMXIMAGE version definition for i.MX chips 65 */ 66 static table_entry_t imximage_versions[] = { 67 {IMXIMAGE_V1, "", " (i.MX25/35/51 compatible)", }, 68 {IMXIMAGE_V2, "", " (i.MX53/6/7 compatible)", }, 69 {-1, "", " (Invalid)", }, 70 }; 71 72 static struct imx_header imximage_header; 73 static uint32_t imximage_version; 74 /* 75 * Image Vector Table Offset 76 * Initialized to a wrong not 4-bytes aligned address to 77 * check if it is was set by the cfg file. 78 */ 79 static uint32_t imximage_ivt_offset = UNDEFINED; 80 static uint32_t imximage_csf_size = UNDEFINED; 81 /* Initial Load Region Size */ 82 static uint32_t imximage_init_loadsize; 83 84 static set_dcd_val_t set_dcd_val; 85 static set_dcd_param_t set_dcd_param; 86 static set_dcd_rst_t set_dcd_rst; 87 static set_imx_hdr_t set_imx_hdr; 88 static uint32_t max_dcd_entries; 89 static uint32_t *header_size_ptr; 90 static uint32_t *csf_ptr; 91 92 static uint32_t get_cfg_value(char *token, char *name, int linenr) 93 { 94 char *endptr; 95 uint32_t value; 96 97 errno = 0; 98 value = strtoul(token, &endptr, 16); 99 if (errno || (token == endptr)) { 100 fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", 101 name, linenr, token); 102 exit(EXIT_FAILURE); 103 } 104 return value; 105 } 106 107 static uint32_t detect_imximage_version(struct imx_header *imx_hdr) 108 { 109 imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; 110 imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; 111 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 112 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 113 114 /* Try to detect V1 */ 115 if ((fhdr_v1->app_code_barker == APP_CODE_BARKER) && 116 (hdr_v1->dcd_table.preamble.barker == DCD_BARKER)) 117 return IMXIMAGE_V1; 118 119 /* Try to detect V2 */ 120 if ((fhdr_v2->header.tag == IVT_HEADER_TAG) && 121 (hdr_v2->dcd_table.header.tag == DCD_HEADER_TAG)) 122 return IMXIMAGE_V2; 123 124 return IMXIMAGE_VER_INVALID; 125 } 126 127 static void err_imximage_version(int version) 128 { 129 fprintf(stderr, 130 "Error: Unsupported imximage version:%d\n", version); 131 132 exit(EXIT_FAILURE); 133 } 134 135 static void set_dcd_val_v1(struct imx_header *imxhdr, char *name, int lineno, 136 int fld, uint32_t value, uint32_t off) 137 { 138 dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; 139 140 switch (fld) { 141 case CFG_REG_SIZE: 142 /* Byte, halfword, word */ 143 if ((value != 1) && (value != 2) && (value != 4)) { 144 fprintf(stderr, "Error: %s[%d] - " 145 "Invalid register size " "(%d)\n", 146 name, lineno, value); 147 exit(EXIT_FAILURE); 148 } 149 dcd_v1->addr_data[off].type = value; 150 break; 151 case CFG_REG_ADDRESS: 152 dcd_v1->addr_data[off].addr = value; 153 break; 154 case CFG_REG_VALUE: 155 dcd_v1->addr_data[off].value = value; 156 break; 157 default: 158 break; 159 160 } 161 } 162 163 static struct dcd_v2_cmd *gd_last_cmd; 164 165 static void set_dcd_param_v2(struct imx_header *imxhdr, uint32_t dcd_len, 166 int32_t cmd) 167 { 168 dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 169 struct dcd_v2_cmd *d = gd_last_cmd; 170 struct dcd_v2_cmd *d2; 171 int len; 172 173 if (!d) 174 d = &dcd_v2->dcd_cmd; 175 d2 = d; 176 len = be16_to_cpu(d->write_dcd_command.length); 177 if (len > 4) 178 d2 = (struct dcd_v2_cmd *)(((char *)d) + len); 179 180 switch (cmd) { 181 case CMD_WRITE_DATA: 182 if ((d->write_dcd_command.tag == DCD_WRITE_DATA_COMMAND_TAG) && 183 (d->write_dcd_command.param == DCD_WRITE_DATA_PARAM)) 184 break; 185 d = d2; 186 d->write_dcd_command.tag = DCD_WRITE_DATA_COMMAND_TAG; 187 d->write_dcd_command.length = cpu_to_be16(4); 188 d->write_dcd_command.param = DCD_WRITE_DATA_PARAM; 189 break; 190 case CMD_WRITE_CLR_BIT: 191 if ((d->write_dcd_command.tag == DCD_WRITE_DATA_COMMAND_TAG) && 192 (d->write_dcd_command.param == DCD_WRITE_CLR_BIT_PARAM)) 193 break; 194 d = d2; 195 d->write_dcd_command.tag = DCD_WRITE_DATA_COMMAND_TAG; 196 d->write_dcd_command.length = cpu_to_be16(4); 197 d->write_dcd_command.param = DCD_WRITE_CLR_BIT_PARAM; 198 break; 199 /* 200 * Check data command only supports one entry, 201 */ 202 case CMD_CHECK_BITS_SET: 203 d = d2; 204 d->write_dcd_command.tag = DCD_CHECK_DATA_COMMAND_TAG; 205 d->write_dcd_command.length = cpu_to_be16(4); 206 d->write_dcd_command.param = DCD_CHECK_BITS_SET_PARAM; 207 break; 208 case CMD_CHECK_BITS_CLR: 209 d = d2; 210 d->write_dcd_command.tag = DCD_CHECK_DATA_COMMAND_TAG; 211 d->write_dcd_command.length = cpu_to_be16(4); 212 d->write_dcd_command.param = DCD_CHECK_BITS_CLR_PARAM; 213 break; 214 default: 215 break; 216 } 217 gd_last_cmd = d; 218 } 219 220 static void set_dcd_val_v2(struct imx_header *imxhdr, char *name, int lineno, 221 int fld, uint32_t value, uint32_t off) 222 { 223 struct dcd_v2_cmd *d = gd_last_cmd; 224 int len; 225 226 len = be16_to_cpu(d->write_dcd_command.length); 227 off = (len - 4) >> 3; 228 229 switch (fld) { 230 case CFG_REG_ADDRESS: 231 d->addr_data[off].addr = cpu_to_be32(value); 232 break; 233 case CFG_REG_VALUE: 234 d->addr_data[off].value = cpu_to_be32(value); 235 off++; 236 d->write_dcd_command.length = cpu_to_be16((off << 3) + 4); 237 break; 238 default: 239 break; 240 241 } 242 } 243 244 /* 245 * Complete setting up the rest field of DCD of V1 246 * such as barker code and DCD data length. 247 */ 248 static void set_dcd_rst_v1(struct imx_header *imxhdr, uint32_t dcd_len, 249 char *name, int lineno) 250 { 251 dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; 252 253 dcd_v1->preamble.barker = DCD_BARKER; 254 dcd_v1->preamble.length = dcd_len * sizeof(dcd_type_addr_data_t); 255 } 256 257 /* 258 * Complete setting up the reset field of DCD of V2 259 * such as DCD tag, version, length, etc. 260 */ 261 static void set_dcd_rst_v2(struct imx_header *imxhdr, uint32_t dcd_len, 262 char *name, int lineno) 263 { 264 dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 265 struct dcd_v2_cmd *d = gd_last_cmd; 266 int len; 267 268 if (!d) 269 d = &dcd_v2->dcd_cmd; 270 len = be16_to_cpu(d->write_dcd_command.length); 271 if (len > 4) 272 d = (struct dcd_v2_cmd *)(((char *)d) + len); 273 274 len = (char *)d - (char *)&dcd_v2->header; 275 276 dcd_v2->header.tag = DCD_HEADER_TAG; 277 dcd_v2->header.length = cpu_to_be16(len); 278 dcd_v2->header.version = DCD_VERSION; 279 } 280 281 static void set_imx_hdr_v1(struct imx_header *imxhdr, uint32_t dcd_len, 282 uint32_t entry_point, uint32_t flash_offset) 283 { 284 imx_header_v1_t *hdr_v1 = &imxhdr->header.hdr_v1; 285 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 286 dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; 287 uint32_t hdr_base; 288 uint32_t header_length = (((char *)&dcd_v1->addr_data[dcd_len].addr) 289 - ((char *)imxhdr)); 290 291 /* Set magic number */ 292 fhdr_v1->app_code_barker = APP_CODE_BARKER; 293 294 /* TODO: check i.MX image V1 handling, for now use 'old' style */ 295 hdr_base = entry_point - 4096; 296 fhdr_v1->app_dest_ptr = hdr_base - flash_offset; 297 fhdr_v1->app_code_jump_vector = entry_point; 298 299 fhdr_v1->dcd_ptr_ptr = hdr_base + offsetof(flash_header_v1_t, dcd_ptr); 300 fhdr_v1->dcd_ptr = hdr_base + offsetof(imx_header_v1_t, dcd_table); 301 302 /* Security feature are not supported */ 303 fhdr_v1->app_code_csf = 0; 304 fhdr_v1->super_root_key = 0; 305 header_size_ptr = (uint32_t *)(((char *)imxhdr) + header_length - 4); 306 } 307 308 static void set_imx_hdr_v2(struct imx_header *imxhdr, uint32_t dcd_len, 309 uint32_t entry_point, uint32_t flash_offset) 310 { 311 imx_header_v2_t *hdr_v2 = &imxhdr->header.hdr_v2; 312 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 313 uint32_t hdr_base; 314 315 /* Set magic number */ 316 fhdr_v2->header.tag = IVT_HEADER_TAG; /* 0xD1 */ 317 fhdr_v2->header.length = cpu_to_be16(sizeof(flash_header_v2_t)); 318 fhdr_v2->header.version = IVT_VERSION; /* 0x40 */ 319 320 fhdr_v2->entry = entry_point; 321 fhdr_v2->reserved1 = fhdr_v2->reserved2 = 0; 322 hdr_base = entry_point - imximage_init_loadsize + 323 flash_offset; 324 fhdr_v2->self = hdr_base; 325 if (dcd_len > 0) 326 fhdr_v2->dcd_ptr = hdr_base 327 + offsetof(imx_header_v2_t, dcd_table); 328 else 329 fhdr_v2->dcd_ptr = 0; 330 fhdr_v2->boot_data_ptr = hdr_base 331 + offsetof(imx_header_v2_t, boot_data); 332 hdr_v2->boot_data.start = entry_point - imximage_init_loadsize; 333 334 fhdr_v2->csf = 0; 335 336 header_size_ptr = &hdr_v2->boot_data.size; 337 csf_ptr = &fhdr_v2->csf; 338 } 339 340 static void set_hdr_func(void) 341 { 342 switch (imximage_version) { 343 case IMXIMAGE_V1: 344 set_dcd_val = set_dcd_val_v1; 345 set_dcd_param = NULL; 346 set_dcd_rst = set_dcd_rst_v1; 347 set_imx_hdr = set_imx_hdr_v1; 348 max_dcd_entries = MAX_HW_CFG_SIZE_V1; 349 break; 350 case IMXIMAGE_V2: 351 gd_last_cmd = NULL; 352 set_dcd_val = set_dcd_val_v2; 353 set_dcd_param = set_dcd_param_v2; 354 set_dcd_rst = set_dcd_rst_v2; 355 set_imx_hdr = set_imx_hdr_v2; 356 max_dcd_entries = MAX_HW_CFG_SIZE_V2; 357 break; 358 default: 359 err_imximage_version(imximage_version); 360 break; 361 } 362 } 363 364 static void print_hdr_v1(struct imx_header *imx_hdr) 365 { 366 imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; 367 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 368 dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; 369 uint32_t size, length, ver; 370 371 size = dcd_v1->preamble.length; 372 if (size > (MAX_HW_CFG_SIZE_V1 * sizeof(dcd_type_addr_data_t))) { 373 fprintf(stderr, 374 "Error: Image corrupt DCD size %d exceed maximum %d\n", 375 (uint32_t)(size / sizeof(dcd_type_addr_data_t)), 376 MAX_HW_CFG_SIZE_V1); 377 exit(EXIT_FAILURE); 378 } 379 380 length = dcd_v1->preamble.length / sizeof(dcd_type_addr_data_t); 381 ver = detect_imximage_version(imx_hdr); 382 383 printf("Image Type: Freescale IMX Boot Image\n"); 384 printf("Image Ver: %x", ver); 385 printf("%s\n", get_table_entry_name(imximage_versions, NULL, ver)); 386 printf("Data Size: "); 387 genimg_print_size(dcd_v1->addr_data[length].type); 388 printf("Load Address: %08x\n", (uint32_t)fhdr_v1->app_dest_ptr); 389 printf("Entry Point: %08x\n", (uint32_t)fhdr_v1->app_code_jump_vector); 390 } 391 392 static void print_hdr_v2(struct imx_header *imx_hdr) 393 { 394 imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; 395 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 396 dcd_v2_t *dcd_v2 = &hdr_v2->dcd_table; 397 uint32_t size, version; 398 399 size = be16_to_cpu(dcd_v2->header.length); 400 if (size > (MAX_HW_CFG_SIZE_V2 * sizeof(dcd_addr_data_t)) + 8) { 401 fprintf(stderr, 402 "Error: Image corrupt DCD size %d exceed maximum %d\n", 403 (uint32_t)(size / sizeof(dcd_addr_data_t)), 404 MAX_HW_CFG_SIZE_V2); 405 exit(EXIT_FAILURE); 406 } 407 408 version = detect_imximage_version(imx_hdr); 409 410 printf("Image Type: Freescale IMX Boot Image\n"); 411 printf("Image Ver: %x", version); 412 printf("%s\n", get_table_entry_name(imximage_versions, NULL, version)); 413 printf("Data Size: "); 414 genimg_print_size(hdr_v2->boot_data.size); 415 printf("Load Address: %08x\n", (uint32_t)fhdr_v2->boot_data_ptr); 416 printf("Entry Point: %08x\n", (uint32_t)fhdr_v2->entry); 417 if (fhdr_v2->csf && (imximage_ivt_offset != UNDEFINED) && 418 (imximage_csf_size != UNDEFINED)) { 419 printf("HAB Blocks: %08x %08x %08x\n", 420 (uint32_t)fhdr_v2->self, 0, 421 hdr_v2->boot_data.size - imximage_ivt_offset - 422 imximage_csf_size); 423 } 424 } 425 426 static void parse_cfg_cmd(struct imx_header *imxhdr, int32_t cmd, char *token, 427 char *name, int lineno, int fld, int dcd_len) 428 { 429 int value; 430 static int cmd_ver_first = ~0; 431 432 switch (cmd) { 433 case CMD_IMAGE_VERSION: 434 imximage_version = get_cfg_value(token, name, lineno); 435 if (cmd_ver_first == 0) { 436 fprintf(stderr, "Error: %s[%d] - IMAGE_VERSION " 437 "command need be the first before other " 438 "valid command in the file\n", name, lineno); 439 exit(EXIT_FAILURE); 440 } 441 cmd_ver_first = 1; 442 set_hdr_func(); 443 break; 444 case CMD_BOOT_FROM: 445 imximage_ivt_offset = get_table_entry_id(imximage_boot_offset, 446 "imximage boot option", token); 447 if (imximage_ivt_offset == -1) { 448 fprintf(stderr, "Error: %s[%d] -Invalid boot device" 449 "(%s)\n", name, lineno, token); 450 exit(EXIT_FAILURE); 451 } 452 453 imximage_init_loadsize = 454 get_table_entry_id(imximage_boot_loadsize, 455 "imximage boot option", token); 456 457 if (imximage_init_loadsize == -1) { 458 fprintf(stderr, 459 "Error: %s[%d] -Invalid boot device(%s)\n", 460 name, lineno, token); 461 exit(EXIT_FAILURE); 462 } 463 464 /* 465 * The SOC loads from the storage starting at address 0 466 * then ensures that the load size contains the offset 467 */ 468 if (imximage_init_loadsize < imximage_ivt_offset) 469 imximage_init_loadsize = imximage_ivt_offset; 470 if (unlikely(cmd_ver_first != 1)) 471 cmd_ver_first = 0; 472 break; 473 case CMD_BOOT_OFFSET: 474 imximage_ivt_offset = get_cfg_value(token, name, lineno); 475 if (unlikely(cmd_ver_first != 1)) 476 cmd_ver_first = 0; 477 break; 478 case CMD_WRITE_DATA: 479 case CMD_WRITE_CLR_BIT: 480 case CMD_CHECK_BITS_SET: 481 case CMD_CHECK_BITS_CLR: 482 value = get_cfg_value(token, name, lineno); 483 if (set_dcd_param) 484 (*set_dcd_param)(imxhdr, dcd_len, cmd); 485 (*set_dcd_val)(imxhdr, name, lineno, fld, value, dcd_len); 486 if (unlikely(cmd_ver_first != 1)) 487 cmd_ver_first = 0; 488 break; 489 case CMD_CSF: 490 if (imximage_version != 2) { 491 fprintf(stderr, 492 "Error: %s[%d] - CSF only supported for VERSION 2(%s)\n", 493 name, lineno, token); 494 exit(EXIT_FAILURE); 495 } 496 imximage_csf_size = get_cfg_value(token, name, lineno); 497 if (unlikely(cmd_ver_first != 1)) 498 cmd_ver_first = 0; 499 break; 500 } 501 } 502 503 static void parse_cfg_fld(struct imx_header *imxhdr, int32_t *cmd, 504 char *token, char *name, int lineno, int fld, int *dcd_len) 505 { 506 int value; 507 508 switch (fld) { 509 case CFG_COMMAND: 510 *cmd = get_table_entry_id(imximage_cmds, 511 "imximage commands", token); 512 if (*cmd < 0) { 513 fprintf(stderr, "Error: %s[%d] - Invalid command" 514 "(%s)\n", name, lineno, token); 515 exit(EXIT_FAILURE); 516 } 517 break; 518 case CFG_REG_SIZE: 519 parse_cfg_cmd(imxhdr, *cmd, token, name, lineno, fld, *dcd_len); 520 break; 521 case CFG_REG_ADDRESS: 522 case CFG_REG_VALUE: 523 switch(*cmd) { 524 case CMD_WRITE_DATA: 525 case CMD_WRITE_CLR_BIT: 526 case CMD_CHECK_BITS_SET: 527 case CMD_CHECK_BITS_CLR: 528 529 value = get_cfg_value(token, name, lineno); 530 if (set_dcd_param) 531 (*set_dcd_param)(imxhdr, *dcd_len, *cmd); 532 (*set_dcd_val)(imxhdr, name, lineno, fld, value, 533 *dcd_len); 534 535 if (fld == CFG_REG_VALUE) { 536 (*dcd_len)++; 537 if (*dcd_len > max_dcd_entries) { 538 fprintf(stderr, "Error: %s[%d] -" 539 "DCD table exceeds maximum size(%d)\n", 540 name, lineno, max_dcd_entries); 541 exit(EXIT_FAILURE); 542 } 543 } 544 break; 545 default: 546 break; 547 } 548 break; 549 default: 550 break; 551 } 552 } 553 static uint32_t parse_cfg_file(struct imx_header *imxhdr, char *name) 554 { 555 FILE *fd = NULL; 556 char *line = NULL; 557 char *token, *saveptr1, *saveptr2; 558 int lineno = 0; 559 int fld; 560 size_t len; 561 int dcd_len = 0; 562 int32_t cmd; 563 564 fd = fopen(name, "r"); 565 if (fd == 0) { 566 fprintf(stderr, "Error: %s - Can't open DCD file\n", name); 567 exit(EXIT_FAILURE); 568 } 569 570 /* 571 * Very simple parsing, line starting with # are comments 572 * and are dropped 573 */ 574 while ((getline(&line, &len, fd)) > 0) { 575 lineno++; 576 577 token = strtok_r(line, "\r\n", &saveptr1); 578 if (token == NULL) 579 continue; 580 581 /* Check inside the single line */ 582 for (fld = CFG_COMMAND, cmd = CMD_INVALID, 583 line = token; ; line = NULL, fld++) { 584 token = strtok_r(line, " \t", &saveptr2); 585 if (token == NULL) 586 break; 587 588 /* Drop all text starting with '#' as comments */ 589 if (token[0] == '#') 590 break; 591 592 parse_cfg_fld(imxhdr, &cmd, token, name, 593 lineno, fld, &dcd_len); 594 } 595 596 } 597 598 (*set_dcd_rst)(imxhdr, dcd_len, name, lineno); 599 fclose(fd); 600 601 /* Exit if there is no BOOT_FROM field specifying the flash_offset */ 602 if (imximage_ivt_offset == FLASH_OFFSET_UNDEFINED) { 603 fprintf(stderr, "Error: No BOOT_FROM tag in %s\n", name); 604 exit(EXIT_FAILURE); 605 } 606 return dcd_len; 607 } 608 609 610 static int imximage_check_image_types(uint8_t type) 611 { 612 if (type == IH_TYPE_IMXIMAGE) 613 return EXIT_SUCCESS; 614 else 615 return EXIT_FAILURE; 616 } 617 618 static int imximage_verify_header(unsigned char *ptr, int image_size, 619 struct image_tool_params *params) 620 { 621 struct imx_header *imx_hdr = (struct imx_header *) ptr; 622 623 if (detect_imximage_version(imx_hdr) == IMXIMAGE_VER_INVALID) 624 return -FDT_ERR_BADSTRUCTURE; 625 626 return 0; 627 } 628 629 static void imximage_print_header(const void *ptr) 630 { 631 struct imx_header *imx_hdr = (struct imx_header *) ptr; 632 uint32_t version = detect_imximage_version(imx_hdr); 633 634 switch (version) { 635 case IMXIMAGE_V1: 636 print_hdr_v1(imx_hdr); 637 break; 638 case IMXIMAGE_V2: 639 print_hdr_v2(imx_hdr); 640 break; 641 default: 642 err_imximage_version(version); 643 break; 644 } 645 } 646 647 static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, 648 struct image_tool_params *params) 649 { 650 struct imx_header *imxhdr = (struct imx_header *)ptr; 651 uint32_t dcd_len; 652 653 /* 654 * In order to not change the old imx cfg file 655 * by adding VERSION command into it, here need 656 * set up function ptr group to V1 by default. 657 */ 658 imximage_version = IMXIMAGE_V1; 659 /* Be able to detect if the cfg file has no BOOT_FROM tag */ 660 imximage_ivt_offset = FLASH_OFFSET_UNDEFINED; 661 imximage_csf_size = 0; 662 set_hdr_func(); 663 664 /* Parse dcd configuration file */ 665 dcd_len = parse_cfg_file(imxhdr, params->imagename); 666 667 if (imximage_version == IMXIMAGE_V2) { 668 if (imximage_init_loadsize < imximage_ivt_offset + 669 sizeof(imx_header_v2_t)) 670 imximage_init_loadsize = imximage_ivt_offset + 671 sizeof(imx_header_v2_t); 672 } 673 674 /* Set the imx header */ 675 (*set_imx_hdr)(imxhdr, dcd_len, params->ep, imximage_ivt_offset); 676 677 /* 678 * ROM bug alert 679 * 680 * MX53 only loads 512 byte multiples in case of SD boot. 681 * MX53 only loads NAND page multiples in case of NAND boot and 682 * supports up to 4096 byte large pages, thus align to 4096. 683 * 684 * The remaining fraction of a block bytes would not be loaded! 685 */ 686 *header_size_ptr = ROUND((sbuf->st_size + imximage_ivt_offset), 4096); 687 688 if (csf_ptr && imximage_csf_size) { 689 *csf_ptr = params->ep - imximage_init_loadsize + 690 *header_size_ptr; 691 *header_size_ptr += imximage_csf_size; 692 } 693 } 694 695 int imximage_check_params(struct image_tool_params *params) 696 { 697 if (!params) 698 return CFG_INVALID; 699 if (!strlen(params->imagename)) { 700 fprintf(stderr, "Error: %s - Configuration file not specified, " 701 "it is needed for imximage generation\n", 702 params->cmdname); 703 return CFG_INVALID; 704 } 705 /* 706 * Check parameters: 707 * XIP is not allowed and verify that incompatible 708 * parameters are not sent at the same time 709 * For example, if list is required a data image must not be provided 710 */ 711 return (params->dflag && (params->fflag || params->lflag)) || 712 (params->fflag && (params->dflag || params->lflag)) || 713 (params->lflag && (params->dflag || params->fflag)) || 714 (params->xflag) || !(strlen(params->imagename)); 715 } 716 717 static int imximage_generate(struct image_tool_params *params, 718 struct image_type_params *tparams) 719 { 720 struct imx_header *imxhdr; 721 size_t alloc_len; 722 struct stat sbuf; 723 char *datafile = params->datafile; 724 uint32_t pad_len; 725 726 memset(&imximage_header, 0, sizeof(imximage_header)); 727 728 /* 729 * In order to not change the old imx cfg file 730 * by adding VERSION command into it, here need 731 * set up function ptr group to V1 by default. 732 */ 733 imximage_version = IMXIMAGE_V1; 734 /* Be able to detect if the cfg file has no BOOT_FROM tag */ 735 imximage_ivt_offset = FLASH_OFFSET_UNDEFINED; 736 imximage_csf_size = 0; 737 set_hdr_func(); 738 739 /* Parse dcd configuration file */ 740 parse_cfg_file(&imximage_header, params->imagename); 741 742 /* TODO: check i.MX image V1 handling, for now use 'old' style */ 743 if (imximage_version == IMXIMAGE_V1) { 744 alloc_len = 4096; 745 } else { 746 if (imximage_init_loadsize < imximage_ivt_offset + 747 sizeof(imx_header_v2_t)) 748 imximage_init_loadsize = imximage_ivt_offset + 749 sizeof(imx_header_v2_t); 750 alloc_len = imximage_init_loadsize - imximage_ivt_offset; 751 } 752 753 if (alloc_len < sizeof(struct imx_header)) { 754 fprintf(stderr, "%s: header error\n", 755 params->cmdname); 756 exit(EXIT_FAILURE); 757 } 758 759 imxhdr = malloc(alloc_len); 760 761 if (!imxhdr) { 762 fprintf(stderr, "%s: malloc return failure: %s\n", 763 params->cmdname, strerror(errno)); 764 exit(EXIT_FAILURE); 765 } 766 767 memset(imxhdr, 0, alloc_len); 768 769 tparams->header_size = alloc_len; 770 tparams->hdr = imxhdr; 771 772 /* determine data image file length */ 773 774 if (stat(datafile, &sbuf) < 0) { 775 fprintf(stderr, "%s: Can't stat %s: %s\n", 776 params->cmdname, datafile, strerror(errno)); 777 exit(EXIT_FAILURE); 778 } 779 780 pad_len = ROUND(sbuf.st_size, 4096) - sbuf.st_size; 781 782 /* TODO: check i.MX image V1 handling, for now use 'old' style */ 783 if (imximage_version == IMXIMAGE_V1) 784 return 0; 785 else 786 return pad_len; 787 } 788 789 790 /* 791 * imximage parameters 792 */ 793 U_BOOT_IMAGE_TYPE( 794 imximage, 795 "Freescale i.MX Boot Image support", 796 0, 797 NULL, 798 imximage_check_params, 799 imximage_verify_header, 800 imximage_print_header, 801 imximage_set_header, 802 NULL, 803 imximage_check_image_types, 804 NULL, 805 imximage_generate 806 ); 807