]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_bootm.c
* Add support for log buffer which can be passed to Linux kernel's
[karo-tx-uboot.git] / common / cmd_bootm.c
1 /*
2  * (C) Copyright 2000-2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * Boot support
26  */
27 #include <common.h>
28 #include <watchdog.h>
29 #include <command.h>
30 #include <cmd_boot.h>
31 #include <image.h>
32 #include <malloc.h>
33 #include <zlib.h>
34 #include <asm/byteorder.h>
35 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
36 #include <rtc.h>
37 #endif
38
39 #ifdef CFG_HUSH_PARSER
40 #include <hush.h>
41 #endif
42
43 #ifdef CONFIG_SHOW_BOOT_PROGRESS
44 # include <status_led.h>
45 # define SHOW_BOOT_PROGRESS(arg)        show_boot_progress(arg)
46 #else
47 # define SHOW_BOOT_PROGRESS(arg)
48 #endif
49
50 #ifdef CFG_INIT_RAM_LOCK
51 #include <asm/cache.h>
52 #endif
53
54 /*
55  * Some systems (for example LWMON) have very short watchdog periods;
56  * we must make sure to split long operations like memmove() or
57  * crc32() into reasonable chunks.
58  */
59 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
60 # define CHUNKSZ (64 * 1024)
61 #endif
62
63 int  gunzip (void *, int, unsigned char *, int *);
64
65 static void *zalloc(void *, unsigned, unsigned);
66 static void zfree(void *, void *, unsigned);
67
68 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
69 static int image_info (unsigned long addr);
70 #endif
71 static void print_type (image_header_t *hdr);
72
73 /*
74  *  Continue booting an OS image; caller already has:
75  *  - copied image header to global variable `header'
76  *  - checked header magic number, checksums (both header & image),
77  *  - verified image architecture (PPC) and type (KERNEL or MULTI),
78  *  - loaded (first part of) image to header load address,
79  *  - disabled interrupts.
80  */
81 typedef void boot_os_Fcn (cmd_tbl_t *cmdtp, int flag,
82                           int   argc, char *argv[],
83                           ulong addr,           /* of image to boot */
84                           ulong *len_ptr,       /* multi-file image length table */
85                           int   verify);        /* getenv("verify")[0] != 'n' */
86
87 #ifndef CONFIG_ARM
88 static boot_os_Fcn do_bootm_linux;
89 #else
90 extern boot_os_Fcn do_bootm_linux;
91 #endif
92 static boot_os_Fcn do_bootm_netbsd;
93 #if (CONFIG_COMMANDS & CFG_CMD_ELF)
94 static boot_os_Fcn do_bootm_vxworks;
95 static boot_os_Fcn do_bootm_qnxelf;
96 int do_bootvx ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] );
97 int do_bootelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[] );
98 #endif /* CFG_CMD_ELF */
99
100 image_header_t header;
101
102 ulong load_addr = CFG_LOAD_ADDR;                /* Default Load Address */
103
104 int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
105 {
106         ulong   iflag;
107         ulong   addr;
108         ulong   data, len, checksum;
109         ulong  *len_ptr;
110         int     i, verify;
111         char    *name, *s;
112         int     (*appl)(cmd_tbl_t *, int, int, char *[]);
113         image_header_t *hdr = &header;
114
115         s = getenv ("verify");
116         verify = (s && (*s == 'n')) ? 0 : 1;
117
118         if (argc < 2) {
119                 addr = load_addr;
120         } else {
121                 addr = simple_strtoul(argv[1], NULL, 16);
122         }
123
124         SHOW_BOOT_PROGRESS (1);
125         printf ("## Booting image at %08lx ...\n", addr);
126
127         /* Copy header so we can blank CRC field for re-calculation */
128         memmove (&header, (char *)addr, sizeof(image_header_t));
129
130         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
131                 printf ("Bad Magic Number\n");
132                 SHOW_BOOT_PROGRESS (-1);
133                 return 1;
134         }
135         SHOW_BOOT_PROGRESS (2);
136
137         data = (ulong)&header;
138         len  = sizeof(image_header_t);
139
140         checksum = ntohl(hdr->ih_hcrc);
141         hdr->ih_hcrc = 0;
142
143         if (crc32 (0, (char *)data, len) != checksum) {
144                 printf ("Bad Header Checksum\n");
145                 SHOW_BOOT_PROGRESS (-2);
146                 return 1;
147         }
148         SHOW_BOOT_PROGRESS (3);
149
150         /* for multi-file images we need the data part, too */
151         print_image_hdr ((image_header_t *)addr);
152
153         data = addr + sizeof(image_header_t);
154         len  = ntohl(hdr->ih_size);
155
156         if (verify) {
157                 printf ("   Verifying Checksum ... ");
158                 if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) {
159                         printf ("Bad Data CRC\n");
160                         SHOW_BOOT_PROGRESS (-3);
161                         return 1;
162                 }
163                 printf ("OK\n");
164         }
165         SHOW_BOOT_PROGRESS (4);
166
167         len_ptr = (ulong *)data;
168
169         if (hdr->ih_arch != IH_CPU_PPC && hdr->ih_arch != IH_CPU_ARM) {
170                 printf ("Unsupported Architecture\n");
171                 SHOW_BOOT_PROGRESS (-4);
172                 return 1;
173         }
174         SHOW_BOOT_PROGRESS (5);
175
176         switch (hdr->ih_type) {
177         case IH_TYPE_STANDALONE:        name = "Standalone Application";
178                                         break;
179         case IH_TYPE_KERNEL:            name = "Kernel Image";
180                                         break;
181         case IH_TYPE_MULTI:             name = "Multi-File Image";
182                                         len  = ntohl(len_ptr[0]);
183                                         /* OS kernel is always the first image */
184                                         data += 8; /* kernel_len + terminator */
185                                         for (i=1; len_ptr[i]; ++i)
186                                                 data += 4;
187                                         break;
188         default: printf ("Wrong Image Type for %s command\n", cmdtp->name);
189                 SHOW_BOOT_PROGRESS (-5);
190                 return 1;
191         }
192         SHOW_BOOT_PROGRESS (6);
193
194         /*
195          * We have reached the point of no return: we are going to
196          * overwrite all exception vector code, so we cannot easily
197          * recover from any failures any more...
198          */
199
200         iflag = disable_interrupts();
201
202         switch (hdr->ih_comp) {
203         case IH_COMP_NONE:
204                 if(hdr->ih_load == addr) {
205                         printf ("   XIP %s ... ", name);
206                 } else {
207 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
208                         size_t l = len;
209                         void *to = (void *)ntohl(hdr->ih_load);
210                         void *from = (void *)data;
211
212                         printf ("   Loading %s ... ", name);
213
214                         while (l > 0) {
215                                 size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
216                                 WATCHDOG_RESET();
217                                 memmove (to, from, tail);
218                                 to += tail;
219                                 from += tail;
220                                 l -= tail;
221                         }
222 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
223                         memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
224 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
225                 }
226                 break;
227         case IH_COMP_GZIP:
228                 printf ("   Uncompressing %s ... ", name);
229                 if (gunzip ((void *)ntohl(hdr->ih_load), 0x400000,
230                             (uchar *)data, (int *)&len) != 0) {
231                         printf ("GUNZIP ERROR - must RESET board to recover\n");
232                         SHOW_BOOT_PROGRESS (-6);
233                         do_reset (cmdtp, flag, argc, argv);
234                 }
235                 break;
236         default:
237                 if (iflag)
238                         enable_interrupts();
239                 printf ("Unimplemented compression type %d\n", hdr->ih_comp);
240                 SHOW_BOOT_PROGRESS (-7);
241                 return 1;
242         }
243         printf ("OK\n");
244         SHOW_BOOT_PROGRESS (7);
245
246         switch (hdr->ih_type) {
247         case IH_TYPE_STANDALONE:
248                 appl = (int (*)(cmd_tbl_t *, int, int, char *[]))ntohl(hdr->ih_ep);
249                 if (iflag)
250                         enable_interrupts();
251
252                 (*appl)(cmdtp, flag, argc-1, &argv[1]);
253                 break;
254         case IH_TYPE_KERNEL:
255         case IH_TYPE_MULTI:
256                 /* handled below */
257                 break;
258         default:
259                 if (iflag)
260                         enable_interrupts();
261                 printf ("Can't boot image type %d\n", hdr->ih_type);
262                 SHOW_BOOT_PROGRESS (-8);
263                 return 1;
264         }
265         SHOW_BOOT_PROGRESS (8);
266
267         switch (hdr->ih_os) {
268         default:                        /* handled by (original) Linux case */
269         case IH_OS_LINUX:
270             do_bootm_linux  (cmdtp, flag, argc, argv,
271                              addr, len_ptr, verify);
272             break;
273         case IH_OS_NETBSD:
274             do_bootm_netbsd (cmdtp, flag, argc, argv,
275                              addr, len_ptr, verify);
276             break;
277 #if (CONFIG_COMMANDS & CFG_CMD_ELF)
278         case IH_OS_VXWORKS:
279             do_bootm_vxworks (cmdtp, flag, argc, argv,
280                               addr, len_ptr, verify);
281             break;
282         case IH_OS_QNX:
283             do_bootm_qnxelf (cmdtp, flag, argc, argv,
284                               addr, len_ptr, verify);
285             break;
286 #endif /* CFG_CMD_ELF */
287         }
288
289         SHOW_BOOT_PROGRESS (-9);
290 #ifdef DEBUG
291         printf ("\n## Control returned to monitor - resetting...\n");
292         do_reset (cmdtp, flag, argc, argv);
293 #endif
294         return 1;
295 }
296
297 #ifndef CONFIG_ARM
298 static void
299 do_bootm_linux (cmd_tbl_t *cmdtp, int flag,
300                 int     argc, char *argv[],
301                 ulong   addr,
302                 ulong   *len_ptr,
303                 int     verify)
304 {
305         DECLARE_GLOBAL_DATA_PTR;
306
307         ulong   sp;
308         ulong   len, checksum;
309         ulong   initrd_start, initrd_end;
310         ulong   cmd_start, cmd_end;
311         ulong   initrd_high;
312         ulong   data;
313         char    *cmdline;
314         char    *s;
315         bd_t    *kbd;
316         void    (*kernel)(bd_t *, ulong, ulong, ulong, ulong);
317         image_header_t *hdr = &header;
318
319         if ((s = getenv ("initrd_high")) != NULL) {
320                 /* a value of "no" or a similar string will act like 0,
321                  * turning the "load high" feature off. This is intentional.
322                  */
323                 initrd_high = simple_strtoul(s, NULL, 16);
324         } else {                        /* not set, no restrictions to load high */
325                 initrd_high = ~0;
326         }
327
328 #ifdef CONFIG_LOGBUFFER
329         kbd=gd->bd;
330         if ((s = getenv ("logstart")) != NULL) {
331                 kbd->bi_sramstart = simple_strtoul(s, NULL, 16);
332                 /* Prevent initrd from overwriting logbuffer */
333                 if (initrd_high < kbd->bi_sramstart)
334                         initrd_high = kbd->bi_sramstart-1024;
335         }
336         debug ("## Logbuffer at 0x%08lX ", kbd->bi_sramstart);
337 #endif
338
339         /*
340          * Booting a (Linux) kernel image
341          *
342          * Allocate space for command line and board info - the
343          * address should be as high as possible within the reach of
344          * the kernel (see CFG_BOOTMAPSZ settings), but in unused
345          * memory, which means far enough below the current stack
346          * pointer.
347          */
348
349         asm( "mr %0,1": "=r"(sp) : );
350
351         debug ("## Current stack ends at 0x%08lX ", sp);
352
353         sp -= 2048;             /* just to be sure */
354         if (sp > CFG_BOOTMAPSZ)
355                 sp = CFG_BOOTMAPSZ;
356         sp &= ~0xF;
357
358         debug ("=> set upper limit to 0x%08lX\n", sp);
359
360         cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF);
361         kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF);
362
363         if ((s = getenv("bootargs")) == NULL)
364                 s = "";
365
366         strcpy (cmdline, s);
367
368         cmd_start    = (ulong)&cmdline[0];
369         cmd_end      = cmd_start + strlen(cmdline);
370
371         *kbd = *(gd->bd);
372
373 #ifdef  DEBUG
374         printf ("## cmdline at 0x%08lX ... 0x%08lX\n", cmd_start, cmd_end);
375
376         do_bdinfo (NULL, 0, 0, NULL);
377 #endif
378
379         if ((s = getenv ("clocks_in_mhz")) != NULL) {
380                 /* convert all clock information to MHz */
381                 kbd->bi_intfreq /= 1000000L;
382                 kbd->bi_busfreq /= 1000000L;
383 #if defined(CONFIG_8260)
384                 kbd->bi_cpmfreq /= 1000000L;
385                 kbd->bi_brgfreq /= 1000000L;
386                 kbd->bi_sccfreq /= 1000000L;
387                 kbd->bi_vco     /= 1000000L;
388 #endif /* CONFIG_8260 */
389         }
390
391         kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep;
392
393         /*
394          * Check if there is an initrd image
395          */
396         if (argc >= 3) {
397                 SHOW_BOOT_PROGRESS (9);
398
399                 addr = simple_strtoul(argv[2], NULL, 16);
400
401                 printf ("## Loading RAMDisk Image at %08lx ...\n", addr);
402
403                 /* Copy header so we can blank CRC field for re-calculation */
404                 memmove (&header, (char *)addr, sizeof(image_header_t));
405
406                 if (hdr->ih_magic  != IH_MAGIC) {
407                         printf ("Bad Magic Number\n");
408                         SHOW_BOOT_PROGRESS (-10);
409                         do_reset (cmdtp, flag, argc, argv);
410                 }
411
412                 data = (ulong)&header;
413                 len  = sizeof(image_header_t);
414
415                 checksum = hdr->ih_hcrc;
416                 hdr->ih_hcrc = 0;
417
418                 if (crc32 (0, (char *)data, len) != checksum) {
419                         printf ("Bad Header Checksum\n");
420                         SHOW_BOOT_PROGRESS (-11);
421                         do_reset (cmdtp, flag, argc, argv);
422                 }
423
424                 SHOW_BOOT_PROGRESS (10);
425
426                 print_image_hdr (hdr);
427
428                 data = addr + sizeof(image_header_t);
429                 len  = hdr->ih_size;
430
431                 if (verify) {
432                         ulong csum = 0;
433 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
434                         ulong cdata = data, edata = cdata + len;
435 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
436
437                         printf ("   Verifying Checksum ... ");
438
439 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
440
441                         while (cdata < edata) {
442                                 ulong chunk = edata - cdata;
443
444                                 if (chunk > CHUNKSZ)
445                                         chunk = CHUNKSZ;
446                                 csum = crc32 (csum, (char *)cdata, chunk);
447                                 cdata += chunk;
448
449                                 WATCHDOG_RESET();
450                         }
451 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
452                         csum = crc32 (0, (char *)data, len);
453 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
454
455                         if (csum != hdr->ih_dcrc) {
456                                 printf ("Bad Data CRC\n");
457                                 SHOW_BOOT_PROGRESS (-12);
458                                 do_reset (cmdtp, flag, argc, argv);
459                         }
460                         printf ("OK\n");
461                 }
462
463                 SHOW_BOOT_PROGRESS (11);
464
465                 if ((hdr->ih_os   != IH_OS_LINUX)       ||
466                     (hdr->ih_arch != IH_CPU_PPC)        ||
467                     (hdr->ih_type != IH_TYPE_RAMDISK)   ) {
468                         printf ("No Linux PPC Ramdisk Image\n");
469                         SHOW_BOOT_PROGRESS (-13);
470                         do_reset (cmdtp, flag, argc, argv);
471                 }
472
473                 /*
474                  * Now check if we have a multifile image
475                  */
476         } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
477                 u_long tail    = ntohl(len_ptr[0]) % 4;
478                 int i;
479
480                 SHOW_BOOT_PROGRESS (13);
481
482                 /* skip kernel length and terminator */
483                 data = (ulong)(&len_ptr[2]);
484                 /* skip any additional image length fields */
485                 for (i=1; len_ptr[i]; ++i)
486                         data += 4;
487                 /* add kernel length, and align */
488                 data += ntohl(len_ptr[0]);
489                 if (tail) {
490                         data += 4 - tail;
491                 }
492
493                 len   = ntohl(len_ptr[1]);
494
495         } else {
496                 /*
497                  * no initrd image
498                  */
499                 SHOW_BOOT_PROGRESS (14);
500
501                 len = data = 0;
502         }
503
504         if (!data) {
505                 debug ("No initrd\n");
506         }
507
508         if (data) {
509                 initrd_start  = (ulong)kbd - len;
510                 initrd_start &= ~(4096 - 1);    /* align on page */
511
512                 if (initrd_high) {
513                         ulong nsp;
514
515                         /*
516                          * the inital ramdisk does not need to be within
517                          * CFG_BOOTMAPSZ as it is not accessed until after
518                          * the mm system is initialised.
519                          *
520                          * do the stack bottom calculation again and see if
521                          * the initrd will fit just below the monitor stack
522                          * bottom without overwriting the area allocated
523                          * above for command line args and board info.
524                          */
525                         asm( "mr %0,1": "=r"(nsp) : );
526                         nsp -= 2048;            /* just to be sure */
527                         nsp &= ~0xF;
528                         if (nsp > initrd_high)  /* limit as specified */
529                                 nsp = initrd_high;
530                         nsp -= len;
531                         nsp &= ~(4096 - 1);     /* align on page */
532                         if (nsp >= sp)
533                                 initrd_start = nsp;
534                 }
535
536                 SHOW_BOOT_PROGRESS (12);
537
538                 debug ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n",
539                         data, data + len - 1, len, len);
540
541                 initrd_end    = initrd_start + len;
542                 printf ("   Loading Ramdisk to %08lx, end %08lx ... ",
543                         initrd_start, initrd_end);
544 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
545                 {
546                         size_t l = len;
547                         void *to = (void *)initrd_start;
548                         void *from = (void *)data;
549
550                         while (l > 0) {
551                                 size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
552                                 WATCHDOG_RESET();
553                                 memmove (to, from, tail);
554                                 to += tail;
555                                 from += tail;
556                                 l -= tail;
557                         }
558                 }
559 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
560                 memmove ((void *)initrd_start, (void *)data, len);
561 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
562                 printf ("OK\n");
563         } else {
564                 initrd_start = 0;
565                 initrd_end = 0;
566         }
567
568
569         debug ("## Transferring control to Linux (at address %08lx) ...\n",
570                 (ulong)kernel);
571
572         SHOW_BOOT_PROGRESS (15);
573
574 #ifdef CFG_INIT_RAM_LOCK
575         unlock_ram_in_cache();
576 #endif
577         /*
578          * Linux Kernel Parameters:
579          *   r3: ptr to board info data
580          *   r4: initrd_start or 0 if no initrd
581          *   r5: initrd_end - unused if r4 is 0
582          *   r6: Start of command line string
583          *   r7: End   of command line string
584          */
585         (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
586 }
587 #endif /* CONFIG_ARM */
588
589 static void
590 do_bootm_netbsd (cmd_tbl_t *cmdtp, int flag,
591                 int     argc, char *argv[],
592                 ulong   addr,
593                 ulong   *len_ptr,
594                 int     verify)
595 {
596         DECLARE_GLOBAL_DATA_PTR;
597
598         image_header_t *hdr = &header;
599
600         void    (*loader)(bd_t *, image_header_t *, char *, char *);
601         image_header_t *img_addr;
602         char     *consdev;
603         char     *cmdline;
604
605
606         /*
607          * Booting a (NetBSD) kernel image
608          *
609          * This process is pretty similar to a standalone application:
610          * The (first part of an multi-) image must be a stage-2 loader,
611          * which in turn is responsible for loading & invoking the actual
612          * kernel.  The only differences are the parameters being passed:
613          * besides the board info strucure, the loader expects a command
614          * line, the name of the console device, and (optionally) the
615          * address of the original image header.
616          */
617
618         img_addr = 0;
619         if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1]))
620                 img_addr = (image_header_t *) addr;
621
622
623         consdev = "";
624 #if   defined (CONFIG_8xx_CONS_SMC1)
625         consdev = "smc1";
626 #elif defined (CONFIG_8xx_CONS_SMC2)
627         consdev = "smc2";
628 #elif defined (CONFIG_8xx_CONS_SCC2)
629         consdev = "scc2";
630 #elif defined (CONFIG_8xx_CONS_SCC3)
631         consdev = "scc3";
632 #endif
633
634         if (argc > 2) {
635                 ulong len;
636                 int   i;
637
638                 for (i=2, len=0 ; i<argc ; i+=1)
639                         len += strlen (argv[i]) + 1;
640                 cmdline = malloc (len);
641
642                 for (i=2, len=0 ; i<argc ; i+=1) {
643                         if (i > 2)
644                                 cmdline[len++] = ' ';
645                         strcpy (&cmdline[len], argv[i]);
646                         len += strlen (argv[i]);
647                 }
648         } else if ((cmdline = getenv("bootargs")) == NULL) {
649                 cmdline = "";
650         }
651
652         loader = (void (*)(bd_t *, image_header_t *, char *, char *)) hdr->ih_ep;
653
654         printf ("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
655                 (ulong)loader);
656
657         SHOW_BOOT_PROGRESS (15);
658
659         /*
660          * NetBSD Stage-2 Loader Parameters:
661          *   r3: ptr to board info data
662          *   r4: image address
663          *   r5: console device
664          *   r6: boot args string
665          */
666         (*loader) (gd->bd, img_addr, consdev, cmdline);
667 }
668
669 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
670 int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
671 {
672         int rcode = 0;
673 #ifndef CFG_HUSH_PARSER
674         if (run_command (getenv ("bootcmd"), flag) < 0) rcode = 1;
675 #else
676         if (parse_string_outer(getenv("bootcmd"),
677                 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0 ) rcode = 1;
678 #endif
679         return rcode;
680 }
681 #endif
682
683 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
684 int do_iminfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
685 {
686         int     arg;
687         ulong   addr;
688         int     rcode=0;
689
690         if (argc < 2) {
691                 return image_info (load_addr);
692         }
693
694         for (arg=1; arg <argc; ++arg) {
695                 addr = simple_strtoul(argv[arg], NULL, 16);
696                 if (image_info (addr) != 0) rcode = 1;
697         }
698         return rcode;
699 }
700
701 static int image_info (ulong addr)
702 {
703         ulong   data, len, checksum;
704         image_header_t *hdr = &header;
705
706         printf ("\n## Checking Image at %08lx ...\n", addr);
707
708         /* Copy header so we can blank CRC field for re-calculation */
709         memmove (&header, (char *)addr, sizeof(image_header_t));
710
711         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
712                 printf ("   Bad Magic Number\n");
713                 return 1;
714         }
715
716         data = (ulong)&header;
717         len  = sizeof(image_header_t);
718
719         checksum = ntohl(hdr->ih_hcrc);
720         hdr->ih_hcrc = 0;
721
722         if (crc32 (0, (char *)data, len) != checksum) {
723                 printf ("   Bad Header Checksum\n");
724                 return 1;
725         }
726
727         /* for multi-file images we need the data part, too */
728         print_image_hdr ((image_header_t *)addr);
729
730         data = addr + sizeof(image_header_t);
731         len  = ntohl(hdr->ih_size);
732
733         printf ("   Verifying Checksum ... ");
734         if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) {
735                 printf ("   Bad Data CRC\n");
736                 return 1;
737         }
738         printf ("OK\n");
739         return 0;
740 }
741 #endif  /* CFG_CMD_IMI */
742
743 void
744 print_image_hdr (image_header_t *hdr)
745 {
746 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
747         time_t timestamp = (time_t)ntohl(hdr->ih_time);
748         struct rtc_time tm;
749 #endif
750
751         printf ("   Image Name:   %.*s\n", IH_NMLEN, hdr->ih_name);
752 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
753         to_tm (timestamp, &tm);
754         printf ("   Created:      %4d-%02d-%02d  %2d:%02d:%02d UTC\n",
755                 tm.tm_year, tm.tm_mon, tm.tm_mday,
756                 tm.tm_hour, tm.tm_min, tm.tm_sec);
757 #endif  /* CFG_CMD_DATE, CONFIG_TIMESTAMP */
758         printf ("   Image Type:   "); print_type(hdr); printf ("\n");
759         printf ("   Data Size:    %d Bytes = ", ntohl(hdr->ih_size));
760         print_size (ntohl(hdr->ih_size), "\n");
761         printf ("   Load Address: %08x\n", ntohl(hdr->ih_load));
762         printf ("   Entry Point:  %08x\n", ntohl(hdr->ih_ep));
763
764         if (hdr->ih_type == IH_TYPE_MULTI) {
765                 int i;
766                 ulong len;
767                 ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t));
768
769                 printf ("   Contents:\n");
770                 for (i=0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) {
771                         printf ("   Image %d: %8ld Bytes = ", i, len);
772                         print_size (len, "\n");
773                 }
774         }
775 }
776
777
778 static void
779 print_type (image_header_t *hdr)
780 {
781         char *os, *arch, *type, *comp;
782
783         switch (hdr->ih_os) {
784         case IH_OS_INVALID:     os = "Invalid OS";              break;
785         case IH_OS_NETBSD:      os = "NetBSD";                  break;
786         case IH_OS_LINUX:       os = "Linux";                   break;
787         case IH_OS_VXWORKS:     os = "VxWorks";                 break;
788         case IH_OS_QNX:         os = "QNX";                     break;
789         case IH_OS_U_BOOT:      os = "U-Boot";                  break;
790         default:                os = "Unknown OS";              break;
791         }
792
793         switch (hdr->ih_arch) {
794         case IH_CPU_INVALID:    arch = "Invalid CPU";           break;
795         case IH_CPU_ALPHA:      arch = "Alpha";                 break;
796         case IH_CPU_ARM:        arch = "ARM";                   break;
797         case IH_CPU_I386:       arch = "Intel x86";             break;
798         case IH_CPU_IA64:       arch = "IA64";                  break;
799         case IH_CPU_MIPS:       arch = "MIPS";                  break;
800         case IH_CPU_MIPS64:     arch = "MIPS 64 Bit";           break;
801         case IH_CPU_PPC:        arch = "PowerPC";               break;
802         case IH_CPU_S390:       arch = "IBM S390";              break;
803         case IH_CPU_SH:         arch = "SuperH";                break;
804         case IH_CPU_SPARC:      arch = "SPARC";                 break;
805         case IH_CPU_SPARC64:    arch = "SPARC 64 Bit";          break;
806         default:                arch = "Unknown Architecture";  break;
807         }
808
809         switch (hdr->ih_type) {
810         case IH_TYPE_INVALID:   type = "Invalid Image";         break;
811         case IH_TYPE_STANDALONE:type = "Standalone Program";    break;
812         case IH_TYPE_KERNEL:    type = "Kernel Image";          break;
813         case IH_TYPE_RAMDISK:   type = "RAMDisk Image";         break;
814         case IH_TYPE_MULTI:     type = "Multi-File Image";      break;
815         case IH_TYPE_FIRMWARE:  type = "Firmware";              break;
816         case IH_TYPE_SCRIPT:    type = "Script";                break;
817         default:                type = "Unknown Image";         break;
818         }
819
820         switch (hdr->ih_comp) {
821         case IH_COMP_NONE:      comp = "uncompressed";          break;
822         case IH_COMP_GZIP:      comp = "gzip compressed";       break;
823         case IH_COMP_BZIP2:     comp = "bzip2 compressed";      break;
824         default:                comp = "unknown compression";   break;
825         }
826
827         printf ("%s %s %s (%s)", arch, os, type, comp);
828 }
829
830 #define ZALLOC_ALIGNMENT        16
831
832 static void *zalloc(void *x, unsigned items, unsigned size)
833 {
834         void *p;
835
836         size *= items;
837         size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
838
839         p = malloc (size);
840
841         return (p);
842 }
843
844 static void zfree(void *x, void *addr, unsigned nb)
845 {
846         free (addr);
847 }
848
849 #define HEAD_CRC        2
850 #define EXTRA_FIELD     4
851 #define ORIG_NAME       8
852 #define COMMENT         0x10
853 #define RESERVED        0xe0
854
855 #define DEFLATED        8
856
857 int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
858 {
859         z_stream s;
860         int r, i, flags;
861
862         /* skip header */
863         i = 10;
864         flags = src[3];
865         if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
866                 printf ("Error: Bad gzipped data\n");
867                 return (-1);
868         }
869         if ((flags & EXTRA_FIELD) != 0)
870                 i = 12 + src[10] + (src[11] << 8);
871         if ((flags & ORIG_NAME) != 0)
872                 while (src[i++] != 0)
873                         ;
874         if ((flags & COMMENT) != 0)
875                 while (src[i++] != 0)
876                         ;
877         if ((flags & HEAD_CRC) != 0)
878                 i += 2;
879         if (i >= *lenp) {
880                 printf ("Error: gunzip out of data in header\n");
881                 return (-1);
882         }
883
884         s.zalloc = zalloc;
885         s.zfree = zfree;
886 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
887         s.outcb = (cb_func)WATCHDOG_RESET;
888 #else
889         s.outcb = Z_NULL;
890 #endif  /* CONFIG_HW_WATCHDOG */
891
892         r = inflateInit2(&s, -MAX_WBITS);
893         if (r != Z_OK) {
894                 printf ("Error: inflateInit2() returned %d\n", r);
895                 return (-1);
896         }
897         s.next_in = src + i;
898         s.avail_in = *lenp - i;
899         s.next_out = dst;
900         s.avail_out = dstlen;
901         r = inflate(&s, Z_FINISH);
902         if (r != Z_OK && r != Z_STREAM_END) {
903                 printf ("Error: inflate() returned %d\n", r);
904                 return (-1);
905         }
906         *lenp = s.next_out - (unsigned char *) dst;
907         inflateEnd(&s);
908
909         return (0);
910 }
911
912 #if (CONFIG_COMMANDS & CFG_CMD_ELF)
913 static void
914 do_bootm_vxworks (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
915                   ulong addr, ulong *len_ptr, int verify)
916 {
917         image_header_t *hdr = &header;
918         char str[80];
919
920         sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */
921         setenv("loadaddr", str);
922         do_bootvx(cmdtp, 0, 0, NULL);
923 }
924
925 static void
926 do_bootm_qnxelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
927                  ulong addr, ulong *len_ptr, int verify)
928 {
929         image_header_t *hdr = &header;
930         char *local_args[2];
931         char str[16];
932
933         sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */
934         local_args[0] = argv[0];
935         local_args[1] = str;    /* and provide it via the arguments */
936         do_bootelf(cmdtp, 0, 2, local_args);
937 }
938 #endif /* CFG_CMD_ELF */