4 * A replacement for ramloader and flashloader, since the loading mechanism
5 * is identical and the difference is just in which call to make to the
8 * (c) 2002-2003 Arcturus Networks Inc.
9 * by Michael Leslie <mleslie@arcturusnetworks.com>,
12 * August 2003 - Oleksandr Zhadan <oleks@arcturusnetworks.com>
13 * load_image_4k() is fixed.
14 * Was wrong link number calculation.
17 /* With uClibc 0.9.26, malloc() is malloc_standard, which uses the slab
18 * allocator. This means that malloc(4096) takes 4 KB of memory, not 8 KB, so
19 * using load_image_4k() should not incur a penalty of 100% overhead.
21 * FIXME: Make load_image4k() recognize opt_stdin.
31 #include <asm/uCbootstrap.h>
35 /****** data declarations: **************************************************/
37 /* Max image size should come at least from (a platform specific
38 * part of) uCbootstrap.h, and at best from a uCbootstrap system call.
39 * For now we will hard-define it here to be 4M - 128K: */
40 #define MAX_IMAGE_SIZE (0x400000 - 0x20000)
43 int opt_ramloader = 0; /* invoke ramloader */
44 int opt_flashloader = 0; /* invoke flashloader */
45 int opt_quiet = 0; /* do not print anything to the screen */
46 int opt_debug = 0; /* print debug info here and in uCbootloader */
47 #define DBG(a1, a2...) if (opt_debug) fprintf(stderr, a1, ##a2)
48 char *opt_filename = NULL; /* filename to load */
49 char *opt_partition = NULL; /* (optional) partition specification to program */
51 int opt_4k = 0; /* Don't use old 4K-based version by default */
53 int opt_noop = 0; /* no bootloader operation */
54 int opt_stdin = 0; /* read image from stdin instead of filesystem */
56 int opt_program_all = 1; /* Use the old bsc_program call to program all
57 * of user flash, rather than partition by partition */
58 int opt_watchdog = 0; /* watchdog must be serviced at key points */
65 /* memory data structures: */
67 uCimage_header header;
68 int header_present = 0;
70 #define BUFFERSIZE 4096
75 #define CARSIZE (65536 - 128)
79 /****** endian handling for uCimage header: *********************************/
81 #if (BYTE_ORDER == BIG_ENDIAN)
82 /* # warning This target is BIG_ENDIAN */
83 /* note "ltoh" = little-endian to host */
84 # define ltoh16(x) bswap_16(x)
85 # define ltoh32(x) __bswap_constant_32(x)
86 #elif (BYTE_ORDER == LITTLE_ENDIAN)
87 /* #warning This target is LITTLE_ENDIAN */
88 /* note "ltoh" = little-endian to host */
89 # define ltoh16(x) (x)
90 # define ltoh32(x) (x)
93 /****** function prototypes: ************************************************/
95 int parse_args(int argc, char *argv[]);
98 _bsc2(int,program,void *,a1,int,a2)
99 _bsc3(int,program2,void *,a1,int,a2,char *,partition)
100 _bsc2(int,ramload,void *,a1,int,a2)
101 _bsc1(int, setbenv, char *, a)
103 int load_image (char *filename); /* malloc, sort, and read 64K blocks */
104 int load_image_4k (char *filename); /* malloc and read 4K blocks */
105 int sort_pointers (void **train, int cars);
106 void deallocate_all (void); /* safely deallocate all major structures */
108 int check_uCimage (uCimage_header *header, FILE *handle);
111 /****** main(): *************************************************************/
113 int main (int argc, char *argv[])
116 if (parse_args (argc, argv))
121 fprintf (stderr, "Opening /dev/watchdog.\n");
122 watchdog = fopen ("/dev/watchdog", "w");
123 if (watchdog == NULL) {
124 perror ("Error opening watchdog device file");
127 fputc('c', watchdog);
132 if (load_image (opt_filename))
135 if (load_image_4k (opt_filename))
140 fputc('c', watchdog);
144 flags = (opt_debug?(PGM_DEBUG):0);
156 ramload(&m, flags | PGM_EXEC_AFTER);
157 else if (opt_flashloader) {
159 program(&m, flags | PGM_ERASE_FIRST | PGM_RESET_AFTER);
162 program2(&m, flags | PGM_ERASE_FIRST | PGM_RESET_AFTER, opt_partition);
164 program2(&m, flags | PGM_ERASE_FIRST | PGM_RESET_AFTER, "0");
169 * PGM_EXEC_AFTER starts the new kernel,
170 * PGM_RESET_AFTER resets the board.
178 /****** function declarations: **********************************************/
181 * parse_args(int argc, char *argv[])
183 * Parse command line arguments and set corresponding
187 int parse_args(int argc, char *argv[])
194 /* fprintf (stderr, "argv[0] = \"%s\"\n", argv[0]); */
195 c = (char *)strrchr (argv[0], '/');
196 if (c == NULL) c = argv[0];
202 if (!strcmp (c, "ramloader"))
204 else if (!strcmp (c, "flashloader"))
207 for (i=1;i<argc;i++) {
208 if (argv[i][0] == '-'){
213 return 1; /* no option */
223 case 'd': opt_debug = 1; break;
224 case 'r': opt_ramloader = 1; break;
225 case 'f': opt_flashloader = 1; break;
226 case 'F': opt_flashloader = 1;
229 case '4': opt_4k = 1; break;
230 case 'n': opt_noop = 1; break;
231 case 'q': opt_quiet = 1; break;
236 case 'w': opt_watchdog = 1; break;
242 "Error: Unknown option \"%s\" - Aborting.\n\n",
248 } else if (opt_filename) {
249 /* If the previous arg was a filename (ie the first non '-' arg, then
250 * this must be a partition spec: "X:"
252 c = strchr(argv[i], ':');
254 *c = 0; /* strip final ':' from partition name */
255 opt_partition = argv[i];
256 if (opt_program_all) {
257 fprintf (stderr, "Error: There is a conflict between programming"
258 " all of flash and partition mode.\n\n");
262 fprintf (stderr, "Error: Only one image is allowed - Aborting.\n\n");
267 opt_filename = argv[i];
270 /* print out options if debug enabled: */
271 DBG("argv[0] = \"%s\"\n", c);
272 DBG("opt_ramloader = %d;\n", opt_ramloader);
273 DBG("opt_flashloader = %d;\n", opt_flashloader);
274 DBG("opt_program_all = %d;\n", opt_program_all);
275 DBG("opt_quiet = %d;\n", opt_quiet);
276 DBG("opt_debug = %d;\n", opt_debug);
277 DBG("opt_filename = %s\n", opt_filename);
278 DBG("opt_partition = %s\n", opt_partition);
279 DBG("opt_4k = %d\n", opt_4k);
280 DBG("opt_noop = %d\n", opt_noop);
281 DBG("opt_stdin = %d\n", opt_stdin);
282 DBG("opt_watchdog = %d\n", opt_watchdog);
284 /* check the option */
285 if(opt_ramloader && opt_flashloader)
288 fprintf(stderr, "Error: You cannot use both -r and -f options.\n");
291 if(opt_ramloader && opt_partition)
294 fprintf(stderr, "Error: specifying a partition to the ramloader makes no sense.\n");
300 fprintf(stderr, "Error: No image given.\n");
304 if (!opt_ramloader && !opt_flashloader) {
307 "Error: neither ramloader (-r) nor flashloader (-f)\n");
309 " selected. Aborting.\n");
316 fprintf (stderr, "Load image file: \"%s\" to %s",
317 opt_filename, opt_ramloader?"ram":"flash");
320 fprintf (stderr, " partition %s\n", opt_partition);
322 fprintf (stderr, "\n");
332 "usage: xloader | ramloader | flashloader\n"
334 " Invoked as \"ramloader\" or \"xloader -r\", this program will\n"
335 " load a kernel image into RAM and pass it to uCbootloader for\n"
337 " Invoked as \"flashloader\" or \"xloader -f\", it will load a\n"
338 " cramfs image and pass it to uCbootloader to be written into\n"
340 " In both cases, this program *will not return*. Once uCbootloader\n"
341 " has been given control, interrupts are disabled, and the new\n"
342 " image is booted.\n"
346 "\t-2\twrite to second flash device(default is the first flash device)\n"
347 "\t-4\tfor 4k-based block, default 64k-based\n"
348 "\t-d\tprint debugging message\n"
349 "\t-f\tinvoke flashloader\n"
350 "\t-F\tinvoke flashloader; use all of user flash\n"
351 "\t-h\tthis help information\n"
352 "\t-n\tDo everything except call the bootloader (noop)\n"
353 "\t-r\tinvoke ramloader\n"
354 "\t-s\tRead new image file from stdin\n"
355 "\t-w\tRefresh /dev/watchdog at key points\n"
356 "\t-q\tdo it quietly, no output to the screen\n\n"
363 int load_image (char *filename)
367 int filesize, i, j, n;
369 int links_per_car, links_over;
372 struct MD5Context md5c;
373 unsigned char digest[16];
378 /* open image file: */
379 image = fopen (filename, "r");
381 perror ("Error opening image file");
387 /* Check for the presence of a uCimage file header: */
389 fread (&header, sizeof(header), 1, image);
390 check_uCimage (&header, image);
392 if (header_present) {
393 filesize = header.data_size;
394 MD5Init(&md5c); /* Initialize MD5 module */
397 /* no uCimage header present: */
399 /* allocate the maximum size, since we do not know
400 * how big the image will be: */
401 filesize = MAX_IMAGE_SIZE;
403 /* stat input file */
404 if (stat (filename, &statbuf)) {
405 perror ("Error stat()ing image file");
408 /* otherwise, all is still OK: */
409 filesize = statbuf.st_size;
414 /* build buffer chain: */
415 links = (int) ((filesize + BUFFERSIZE -1) / BUFFERSIZE);
416 /* chain = (void *)malloc (links * sizeof (void *)); */
418 /* build link train: */
419 links_per_car = CARSIZE / BUFFERSIZE;
420 cars = 1 + links / links_per_car;
422 /* Can we fit the chain into the last car? */
423 /* How many links in the last car? */
424 links_over = links - (cars - 1) * links_per_car;
425 if ((CARSIZE - links_over*BUFFERSIZE) <
426 links * sizeof (void *)) {
427 /* then the chain can not be placed in the last car;
428 * allocate one more.*/
430 links_over = links - (cars - 1) * links_per_car;
431 if (links_over < 0) links_over = 0;
434 /* allocate the array of cars: */
435 /* note: this array can be discarded once the chain of links
436 * has been mapped onto the actual buffers */
437 train = (void *)malloc(cars * sizeof (void *));
438 if ( train == NULL) {
440 fprintf (stderr, "Error allocating train\n");
443 memset (train, 0, cars * sizeof (void *));
445 /* allocate the cars: */
446 for (i=0;i<cars;i++) {
447 train[i] = (void *)malloc(CARSIZE);
448 if (train[i] == NULL) {
450 fprintf (stderr, "Error allocating car %d\n", i);
451 /* before we return, free all allocated memories */
455 DBG("train[%d] = %p\n", i, train[i]);
459 sort_pointers (train, cars);
461 /* map the chain into the last car: */
462 chain = (void *)(train[cars-1]) + (links_over * BUFFERSIZE);
464 /* allocate links into the cars: */
465 for (i=0;i<cars;i++,j++) {
466 DBG("\ntrain[%d] = %p cars:\n", i, train[i]);
467 for (j=0;j<links_per_car;j++) {
468 if (i*links_per_car+j >= links)
470 chain[i*links_per_car+j] = train[i] + (BUFFERSIZE * j);
471 DBG(" 0x%08x", (unsigned int)chain[i*links_per_car+j]);
475 DBG("\nfilesize = %d, links = %d\n", filesize, links);
476 DBG("cars = %d, links_per_car = %d, links_over = %d\n", cars, links_per_car, links_over);
477 DBG("car[%d] = %p, chain = %p\n", cars-1, train[cars-1], chain);
481 /* populate chain with image file: */
482 for (i=0;i<cars;i++) {
483 if ((i+1)*links_per_car <= links)
488 n = fread (train[i], 1, BUFFERSIZE * j, image);
491 fprintf(stderr, "fread %d bytes to car[%d] = %p\n",
494 percent = (((i*links_per_car+j)+1) * 100)/links;
495 /* if (percent%10 == 0) */
497 fprintf (stderr, "\r%d%%", percent);
500 /* Compute MD5 as we read the file: */
502 MD5Update (&md5c, (char *)(train[i]), n);
507 if (n < BUFFERSIZE * j) {
508 if (opt_stdin && !header_present) {
509 /* assume the transmission has finished */
512 if (bytes_read != filesize) {
513 ferror_image = ferror (image);
515 fprintf (stderr, "Error #%d reading from image file\n",
524 if (!opt_debug && !opt_quiet)
525 fprintf (stderr, "\n");
527 if (opt_stdin && !feof(image)) {
528 if (bytes_read != filesize) {
530 fprintf (stderr, "Image too big, max %d\n", filesize);
541 filesize = bytes_read;
542 DBG("size of received file = %d bytes\n", filesize);
545 /* NOTE THAT we should have some kind of header and / or footer to verify
546 * that our image is error free. For starters, make sure it's not empty.
551 fprintf(stderr, "Image is empty.\n");
557 fputc('c', watchdog);
562 if (header_present) {
563 char buf[42], ascii_md5[34];
566 MD5Final (&(digest[0]), &md5c);
569 printf ("Checking MD5 signature... ");
571 /* print the signature to a string: */
573 sprintf (&(ascii_md5[i*2]), "%02x", digest[i]);
575 /* Compare with given digest: */
577 if (digest[i] != header.md5sum[i]) {
578 printf ("ERROR: MD5 digest mismatch\n");
579 printf ("MD5 digest calculated as: %s\n", ascii_md5);
580 printf ("failed to match given MD5: ");
582 printf ("%02x", header.md5sum[i]);
589 printf ("verified\n");
592 fputc('c', watchdog);
596 if (opt_flashloader) {
597 /* write uCbootstrap envars for the image: */
599 sprintf (buf, "p_%s_SIZE=%d", opt_partition, header.data_size);
602 sprintf (buf, "p_%s_MD5=%s", opt_partition, ascii_md5);
607 } /* endif header_present */
611 /* set uCbootloader arguments: */
613 m.offset = (void *)chain;
623 int sort_pointers (void **pointer, int N)
631 for (j=i+1;j<N;j++) {
632 if ((unsigned long int)pointer[j] < (unsigned long int)p) {
634 pointer[j] = pointer[i];
644 int load_image_4k (char *filename)
652 /* stat input file */
653 if (stat (filename, &statbuf)) {
654 perror ("Error stat()ing image file");
658 /* otherwise, all is still OK: */
659 filesize = statbuf.st_size;
661 /* build buffer chain: */
664 links = filesize / BUFFERSIZE;
665 if ( filesize % BUFFERSIZE )
668 DBG(" %d \n", links );
669 DBG("pointer chain: ");
670 chain_tmp = (void *)malloc (links * sizeof (void *)); /* Temporary chain */
671 DBG(" 0x%08x\n", (unsigned int)chain_tmp);
673 for (i=0;i<links;i++) {
674 chain_tmp[i] = (void *)malloc (BUFFERSIZE);
675 DBG(" 0x%08x", (unsigned int)chain_tmp[i]);
676 if (chain_tmp[i] == NULL) {
677 fprintf (stderr, "Error allocating chain link %d\n", i);
681 DBG("\npointer chain: ");
682 chain = (void *)malloc (links * sizeof (void *)); /* Link pointers have to be at the end */
683 DBG(" 0x%08x\n", (unsigned int)chain);
685 for (i=0; i<links; i++) /* Dup the chain */
686 chain[i] = chain_tmp[i];
688 DBG("filesize = %d\n", filesize);
690 /* open image file: */
691 image = fopen (filename, "r");
693 perror ("Error opening image file");
697 /* populate chain with image file: */
698 for (i=0;i<links;i++) {
699 n = fread (chain[i], 1, BUFFERSIZE, image);
703 "fread %d bytes to chain[%d] = %p\n", n, i,chain[i]);
705 percent = ((i+1) * 100)/links;
707 fprintf (stderr, "\r%d%%", percent);
710 if ((n < BUFFERSIZE) && (BUFFERSIZE*i + n < filesize)) {
711 ferror_image = ferror (image);
712 fprintf (stderr, "Error #%d reading from image file\n",
718 if (!opt_debug) fprintf (stderr, "\n");
722 /* set uCbootloader arguments: */
724 m.offset = (void *)chain;
730 int check_uCimage (uCimage_header *header, FILE *handle)
734 /* Check magic in header */
735 for (i=0;i<sizeof(header->magic);i++) {
736 if (header->magic[i] != UCHEADER_MAGIC[i]) {
738 fprintf (stderr, "Header magic[%d] not: \"%s\" instead: \"%s\"\n",
739 i, UCHEADER_MAGIC, header->magic);
740 fprintf (stderr, "uCimage header not detected.\n");
742 return (1); /* header not found */
748 /* TODO: check reported header size, seek to data */
750 /* Convert from little-endian to host byte order *in place*
753 header->header_size = ltoh32(header->header_size);
754 DBG ("header_size reported as: %10d\n", header->header_size);
757 header->data_size = ltoh32(header->data_size);
758 fprintf (stdout, "data_size reported as: %10d\n", header->data_size);
760 /* header date code */
761 fprintf (stdout, "date code reported as: \"%s\"\n", header->datecode);
764 fprintf (stdout, "name reported as: \"%s\"\n", header->name);
767 fprintf (stdout, "MD5 digest reported as: ");
769 fprintf (stdout, "%02x", header->md5sum[i]);
770 fprintf (stdout, "\n");
773 /* read image and do MD5: */
774 while (!feof(infile)) {
775 n = fread (buf, 1, BUFFERSIZE, infile);
777 MD5Update (&md5c, buf, n);
780 MD5Final (digest, &md5c);
787 /****************************************************************************/
789 /* safely deallocate all major structures */
790 void deallocate_all (void)
795 for (i=0;i<cars;i++) {
796 if (train[i] != NULL) {
797 DBG("deallocate_all(): train[%d] == %p\n", i, train[i]);
805 /****************************************************************************/