1 /* 2 * (C) Copyright 2000-2004 3 * DENX Software Engineering 4 * Wolfgang Denk, wd@denx.de 5 * All rights reserved. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 * MA 02111-1307 USA 21 */ 22 23 #include "mkimage.h" 24 #include <image.h> 25 26 extern int errno; 27 28 #ifndef MAP_FAILED 29 #define MAP_FAILED (-1) 30 #endif 31 32 extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len); 33 static void copy_file (int, const char *, int); 34 static void usage (void); 35 36 char *datafile; 37 char *imagefile; 38 char *cmdname; 39 40 int dflag = 0; 41 int eflag = 0; 42 int lflag = 0; 43 int vflag = 0; 44 int xflag = 0; 45 int opt_os = IH_OS_LINUX; 46 int opt_arch = IH_ARCH_PPC; 47 int opt_type = IH_TYPE_KERNEL; 48 int opt_comp = IH_COMP_GZIP; 49 50 image_header_t header; 51 image_header_t *hdr = &header; 52 53 int 54 main (int argc, char **argv) 55 { 56 int ifd; 57 uint32_t checksum; 58 uint32_t addr; 59 uint32_t ep; 60 struct stat sbuf; 61 unsigned char *ptr; 62 char *name = ""; 63 64 cmdname = *argv; 65 66 addr = ep = 0; 67 68 while (--argc > 0 && **++argv == '-') { 69 while (*++*argv) { 70 switch (**argv) { 71 case 'l': 72 lflag = 1; 73 break; 74 case 'A': 75 if ((--argc <= 0) || 76 (opt_arch = genimg_get_arch_id (*++argv)) < 0) 77 usage (); 78 goto NXTARG; 79 case 'C': 80 if ((--argc <= 0) || 81 (opt_comp = genimg_get_comp_id (*++argv)) < 0) 82 usage (); 83 goto NXTARG; 84 case 'O': 85 if ((--argc <= 0) || 86 (opt_os = genimg_get_os_id (*++argv)) < 0) 87 usage (); 88 goto NXTARG; 89 case 'T': 90 if ((--argc <= 0) || 91 (opt_type = genimg_get_type_id (*++argv)) < 0) 92 usage (); 93 goto NXTARG; 94 95 case 'a': 96 if (--argc <= 0) 97 usage (); 98 addr = strtoul (*++argv, (char **)&ptr, 16); 99 if (*ptr) { 100 fprintf (stderr, 101 "%s: invalid load address %s\n", 102 cmdname, *argv); 103 exit (EXIT_FAILURE); 104 } 105 goto NXTARG; 106 case 'd': 107 if (--argc <= 0) 108 usage (); 109 datafile = *++argv; 110 dflag = 1; 111 goto NXTARG; 112 case 'e': 113 if (--argc <= 0) 114 usage (); 115 ep = strtoul (*++argv, (char **)&ptr, 16); 116 if (*ptr) { 117 fprintf (stderr, 118 "%s: invalid entry point %s\n", 119 cmdname, *argv); 120 exit (EXIT_FAILURE); 121 } 122 eflag = 1; 123 goto NXTARG; 124 case 'n': 125 if (--argc <= 0) 126 usage (); 127 name = *++argv; 128 goto NXTARG; 129 case 'v': 130 vflag++; 131 break; 132 case 'x': 133 xflag++; 134 break; 135 default: 136 usage (); 137 } 138 } 139 NXTARG: ; 140 } 141 142 if ((argc != 1) || ((lflag ^ dflag) == 0)) 143 usage(); 144 145 if (!eflag) { 146 ep = addr; 147 /* If XIP, entry point must be after the U-Boot header */ 148 if (xflag) 149 ep += image_get_header_size (); 150 } 151 152 /* 153 * If XIP, ensure the entry point is equal to the load address plus 154 * the size of the U-Boot header. 155 */ 156 if (xflag) { 157 if (ep != addr + image_get_header_size ()) { 158 fprintf (stderr, 159 "%s: For XIP, the entry point must be the load addr + %lu\n", 160 cmdname, 161 (unsigned long)image_get_header_size ()); 162 exit (EXIT_FAILURE); 163 } 164 } 165 166 imagefile = *argv; 167 168 if (lflag) { 169 ifd = open(imagefile, O_RDONLY|O_BINARY); 170 } else { 171 ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); 172 } 173 174 if (ifd < 0) { 175 fprintf (stderr, "%s: Can't open %s: %s\n", 176 cmdname, imagefile, strerror(errno)); 177 exit (EXIT_FAILURE); 178 } 179 180 if (lflag) { 181 int len; 182 char *data; 183 /* 184 * list header information of existing image 185 */ 186 if (fstat(ifd, &sbuf) < 0) { 187 fprintf (stderr, "%s: Can't stat %s: %s\n", 188 cmdname, imagefile, strerror(errno)); 189 exit (EXIT_FAILURE); 190 } 191 192 if ((unsigned)sbuf.st_size < image_get_header_size ()) { 193 fprintf (stderr, 194 "%s: Bad size: \"%s\" is no valid image\n", 195 cmdname, imagefile); 196 exit (EXIT_FAILURE); 197 } 198 199 ptr = (unsigned char *)mmap(0, sbuf.st_size, 200 PROT_READ, MAP_SHARED, ifd, 0); 201 if ((caddr_t)ptr == (caddr_t)-1) { 202 fprintf (stderr, "%s: Can't read %s: %s\n", 203 cmdname, imagefile, strerror(errno)); 204 exit (EXIT_FAILURE); 205 } 206 207 /* 208 * image_check_hcrc() creates copy of header so that 209 * we can blank out the checksum field for checking - 210 * this can't be done on the PROT_READ mapped data. 211 */ 212 hdr = (image_header_t *)ptr; 213 214 if (!image_check_magic (hdr)) { 215 fprintf (stderr, 216 "%s: Bad Magic Number: \"%s\" is no valid image\n", 217 cmdname, imagefile); 218 exit (EXIT_FAILURE); 219 } 220 221 if (!image_check_hcrc (hdr)) { 222 fprintf (stderr, 223 "%s: ERROR: \"%s\" has bad header checksum!\n", 224 cmdname, imagefile); 225 exit (EXIT_FAILURE); 226 } 227 228 data = (char *)image_get_data (hdr); 229 len = sbuf.st_size - image_get_header_size (); 230 231 if (crc32(0, data, len) != image_get_dcrc (hdr)) { 232 fprintf (stderr, 233 "%s: ERROR: \"%s\" has corrupted data!\n", 234 cmdname, imagefile); 235 exit (EXIT_FAILURE); 236 } 237 238 /* for multi-file images we need the data part, too */ 239 image_print_contents_noindent ((image_header_t *)ptr); 240 241 (void) munmap((void *)ptr, sbuf.st_size); 242 (void) close (ifd); 243 244 exit (EXIT_SUCCESS); 245 } 246 247 /* 248 * Must be -w then: 249 * 250 * write dummy header, to be fixed later 251 */ 252 memset (hdr, 0, image_get_header_size ()); 253 254 if (write(ifd, hdr, image_get_header_size ()) != image_get_header_size ()) { 255 fprintf (stderr, "%s: Write error on %s: %s\n", 256 cmdname, imagefile, strerror(errno)); 257 exit (EXIT_FAILURE); 258 } 259 260 if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) { 261 char *file = datafile; 262 uint32_t size; 263 264 for (;;) { 265 char *sep = NULL; 266 267 if (file) { 268 if ((sep = strchr(file, ':')) != NULL) { 269 *sep = '\0'; 270 } 271 272 if (stat (file, &sbuf) < 0) { 273 fprintf (stderr, "%s: Can't stat %s: %s\n", 274 cmdname, file, strerror(errno)); 275 exit (EXIT_FAILURE); 276 } 277 size = cpu_to_uimage (sbuf.st_size); 278 } else { 279 size = 0; 280 } 281 282 if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { 283 fprintf (stderr, "%s: Write error on %s: %s\n", 284 cmdname, imagefile, strerror(errno)); 285 exit (EXIT_FAILURE); 286 } 287 288 if (!file) { 289 break; 290 } 291 292 if (sep) { 293 *sep = ':'; 294 file = sep + 1; 295 } else { 296 file = NULL; 297 } 298 } 299 300 file = datafile; 301 302 for (;;) { 303 char *sep = strchr(file, ':'); 304 if (sep) { 305 *sep = '\0'; 306 copy_file (ifd, file, 1); 307 *sep++ = ':'; 308 file = sep; 309 } else { 310 copy_file (ifd, file, 0); 311 break; 312 } 313 } 314 } else { 315 copy_file (ifd, datafile, 0); 316 } 317 318 /* We're a bit of paranoid */ 319 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__) 320 (void) fdatasync (ifd); 321 #else 322 (void) fsync (ifd); 323 #endif 324 325 if (fstat(ifd, &sbuf) < 0) { 326 fprintf (stderr, "%s: Can't stat %s: %s\n", 327 cmdname, imagefile, strerror(errno)); 328 exit (EXIT_FAILURE); 329 } 330 331 ptr = (unsigned char *)mmap(0, sbuf.st_size, 332 PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); 333 if (ptr == (unsigned char *)MAP_FAILED) { 334 fprintf (stderr, "%s: Can't map %s: %s\n", 335 cmdname, imagefile, strerror(errno)); 336 exit (EXIT_FAILURE); 337 } 338 339 hdr = (image_header_t *)ptr; 340 341 checksum = crc32 (0, 342 (const char *)(ptr + image_get_header_size ()), 343 sbuf.st_size - image_get_header_size () 344 ); 345 346 /* Build new header */ 347 image_set_magic (hdr, IH_MAGIC); 348 image_set_time (hdr, sbuf.st_mtime); 349 image_set_size (hdr, sbuf.st_size - image_get_header_size ()); 350 image_set_load (hdr, addr); 351 image_set_ep (hdr, ep); 352 image_set_dcrc (hdr, checksum); 353 image_set_os (hdr, opt_os); 354 image_set_arch (hdr, opt_arch); 355 image_set_type (hdr, opt_type); 356 image_set_comp (hdr, opt_comp); 357 358 image_set_name (hdr, name); 359 360 checksum = crc32 (0, (const char *)hdr, image_get_header_size ()); 361 362 image_set_hcrc (hdr, checksum); 363 364 image_print_contents_noindent (hdr); 365 366 (void) munmap((void *)ptr, sbuf.st_size); 367 368 /* We're a bit of paranoid */ 369 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__) && !defined(__APPLE__) 370 (void) fdatasync (ifd); 371 #else 372 (void) fsync (ifd); 373 #endif 374 375 if (close(ifd)) { 376 fprintf (stderr, "%s: Write error on %s: %s\n", 377 cmdname, imagefile, strerror(errno)); 378 exit (EXIT_FAILURE); 379 } 380 381 exit (EXIT_SUCCESS); 382 } 383 384 static void 385 copy_file (int ifd, const char *datafile, int pad) 386 { 387 int dfd; 388 struct stat sbuf; 389 unsigned char *ptr; 390 int tail; 391 int zero = 0; 392 int offset = 0; 393 int size; 394 395 if (vflag) { 396 fprintf (stderr, "Adding Image %s\n", datafile); 397 } 398 399 if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { 400 fprintf (stderr, "%s: Can't open %s: %s\n", 401 cmdname, datafile, strerror(errno)); 402 exit (EXIT_FAILURE); 403 } 404 405 if (fstat(dfd, &sbuf) < 0) { 406 fprintf (stderr, "%s: Can't stat %s: %s\n", 407 cmdname, datafile, strerror(errno)); 408 exit (EXIT_FAILURE); 409 } 410 411 ptr = (unsigned char *)mmap(0, sbuf.st_size, 412 PROT_READ, MAP_SHARED, dfd, 0); 413 if (ptr == (unsigned char *)MAP_FAILED) { 414 fprintf (stderr, "%s: Can't read %s: %s\n", 415 cmdname, datafile, strerror(errno)); 416 exit (EXIT_FAILURE); 417 } 418 419 if (xflag) { 420 unsigned char *p = NULL; 421 /* 422 * XIP: do not append the image_header_t at the 423 * beginning of the file, but consume the space 424 * reserved for it. 425 */ 426 427 if ((unsigned)sbuf.st_size < image_get_header_size ()) { 428 fprintf (stderr, 429 "%s: Bad size: \"%s\" is too small for XIP\n", 430 cmdname, datafile); 431 exit (EXIT_FAILURE); 432 } 433 434 for (p = ptr; p < ptr + image_get_header_size (); p++) { 435 if ( *p != 0xff ) { 436 fprintf (stderr, 437 "%s: Bad file: \"%s\" has invalid buffer for XIP\n", 438 cmdname, datafile); 439 exit (EXIT_FAILURE); 440 } 441 } 442 443 offset = image_get_header_size (); 444 } 445 446 size = sbuf.st_size - offset; 447 if (write(ifd, ptr + offset, size) != size) { 448 fprintf (stderr, "%s: Write error on %s: %s\n", 449 cmdname, imagefile, strerror(errno)); 450 exit (EXIT_FAILURE); 451 } 452 453 if (pad && ((tail = size % 4) != 0)) { 454 455 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { 456 fprintf (stderr, "%s: Write error on %s: %s\n", 457 cmdname, imagefile, strerror(errno)); 458 exit (EXIT_FAILURE); 459 } 460 } 461 462 (void) munmap((void *)ptr, sbuf.st_size); 463 (void) close (dfd); 464 } 465 466 void 467 usage () 468 { 469 fprintf (stderr, "Usage: %s -l image\n" 470 " -l ==> list image header information\n" 471 " %s [-x] -A arch -O os -T type -C comp " 472 "-a addr -e ep -n name -d data_file[:data_file...] image\n", 473 cmdname, cmdname); 474 fprintf (stderr, " -A ==> set architecture to 'arch'\n" 475 " -O ==> set operating system to 'os'\n" 476 " -T ==> set image type to 'type'\n" 477 " -C ==> set compression type 'comp'\n" 478 " -a ==> set load address to 'addr' (hex)\n" 479 " -e ==> set entry point to 'ep' (hex)\n" 480 " -n ==> set image name to 'name'\n" 481 " -d ==> use image data from 'datafile'\n" 482 " -x ==> set XIP (execute in place)\n" 483 ); 484 exit (EXIT_FAILURE); 485 } 486