]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_bootm.c
e8ce40d69ca7554e58b959841e3e99526800b99d
[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         /*
329          * Booting a (Linux) kernel image
330          *
331          * Allocate space for command line and board info - the
332          * address should be as high as possible within the reach of
333          * the kernel (see CFG_BOOTMAPSZ settings), but in unused
334          * memory, which means far enough below the current stack
335          * pointer.
336          */
337
338         asm( "mr %0,1": "=r"(sp) : );
339
340 #ifdef  DEBUG
341         printf ("## Current stack ends at 0x%08lX ", sp);
342 #endif
343         sp -= 2048;             /* just to be sure */
344         if (sp > CFG_BOOTMAPSZ)
345                 sp = CFG_BOOTMAPSZ;
346         sp &= ~0xF;
347
348 #ifdef  DEBUG
349         printf ("=> set upper limit to 0x%08lX\n", sp);
350 #endif
351         cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF);
352         kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF);
353
354         if ((s = getenv("bootargs")) == NULL)
355                 s = "";
356
357         strcpy (cmdline, s);
358
359         cmd_start    = (ulong)&cmdline[0];
360         cmd_end      = cmd_start + strlen(cmdline);
361
362         *kbd = *(gd->bd);
363
364 #ifdef  DEBUG
365         printf ("## cmdline at 0x%08lX ... 0x%08lX\n", cmd_start, cmd_end);
366
367         do_bdinfo (NULL, 0, 0, NULL);
368 #endif
369
370         if ((s = getenv ("clocks_in_mhz")) != NULL) {
371                 /* convert all clock information to MHz */
372                 kbd->bi_intfreq /= 1000000L;
373                 kbd->bi_busfreq /= 1000000L;
374 #if defined(CONFIG_8260)
375                 kbd->bi_cpmfreq /= 1000000L;
376                 kbd->bi_brgfreq /= 1000000L;
377                 kbd->bi_sccfreq /= 1000000L;
378                 kbd->bi_vco     /= 1000000L;
379 #endif /* CONFIG_8260 */
380         }
381
382         kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep;
383
384         /*
385          * Check if there is an initrd image
386          */
387         if (argc >= 3) {
388                 SHOW_BOOT_PROGRESS (9);
389
390                 addr = simple_strtoul(argv[2], NULL, 16);
391
392                 printf ("## Loading RAMDisk Image at %08lx ...\n", addr);
393
394                 /* Copy header so we can blank CRC field for re-calculation */
395                 memmove (&header, (char *)addr, sizeof(image_header_t));
396
397                 if (hdr->ih_magic  != IH_MAGIC) {
398                         printf ("Bad Magic Number\n");
399                         SHOW_BOOT_PROGRESS (-10);
400                         do_reset (cmdtp, flag, argc, argv);
401                 }
402
403                 data = (ulong)&header;
404                 len  = sizeof(image_header_t);
405
406                 checksum = hdr->ih_hcrc;
407                 hdr->ih_hcrc = 0;
408
409                 if (crc32 (0, (char *)data, len) != checksum) {
410                         printf ("Bad Header Checksum\n");
411                         SHOW_BOOT_PROGRESS (-11);
412                         do_reset (cmdtp, flag, argc, argv);
413                 }
414
415                 SHOW_BOOT_PROGRESS (10);
416
417                 print_image_hdr (hdr);
418
419                 data = addr + sizeof(image_header_t);
420                 len  = hdr->ih_size;
421
422                 if (verify) {
423                         ulong csum = 0;
424 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
425                         ulong cdata = data, edata = cdata + len;
426 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
427
428                         printf ("   Verifying Checksum ... ");
429
430 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
431
432                         while (cdata < edata) {
433                                 ulong chunk = edata - cdata;
434
435                                 if (chunk > CHUNKSZ)
436                                         chunk = CHUNKSZ;
437                                 csum = crc32 (csum, (char *)cdata, chunk);
438                                 cdata += chunk;
439
440                                 WATCHDOG_RESET();
441                         }
442 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
443                         csum = crc32 (0, (char *)data, len);
444 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
445
446                         if (csum != hdr->ih_dcrc) {
447                                 printf ("Bad Data CRC\n");
448                                 SHOW_BOOT_PROGRESS (-12);
449                                 do_reset (cmdtp, flag, argc, argv);
450                         }
451                         printf ("OK\n");
452                 }
453
454                 SHOW_BOOT_PROGRESS (11);
455
456                 if ((hdr->ih_os   != IH_OS_LINUX)       ||
457                     (hdr->ih_arch != IH_CPU_PPC)        ||
458                     (hdr->ih_type != IH_TYPE_RAMDISK)   ) {
459                         printf ("No Linux PPC Ramdisk Image\n");
460                         SHOW_BOOT_PROGRESS (-13);
461                         do_reset (cmdtp, flag, argc, argv);
462                 }
463
464                 /*
465                  * Now check if we have a multifile image
466                  */
467         } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
468                 u_long tail    = ntohl(len_ptr[0]) % 4;
469                 int i;
470
471                 SHOW_BOOT_PROGRESS (13);
472
473                 /* skip kernel length and terminator */
474                 data = (ulong)(&len_ptr[2]);
475                 /* skip any additional image length fields */
476                 for (i=1; len_ptr[i]; ++i)
477                         data += 4;
478                 /* add kernel length, and align */
479                 data += ntohl(len_ptr[0]);
480                 if (tail) {
481                         data += 4 - tail;
482                 }
483
484                 len   = ntohl(len_ptr[1]);
485
486         } else {
487                 /*
488                  * no initrd image
489                  */
490                 SHOW_BOOT_PROGRESS (14);
491
492                 len = data = 0;
493         }
494
495 #ifdef  DEBUG
496         if (!data) {
497                 printf ("No initrd\n");
498         }
499 #endif
500
501         if (data) {
502                 initrd_start  = (ulong)kbd - len;
503                 initrd_start &= ~(4096 - 1);    /* align on page */
504
505                 if (initrd_high) {
506                         ulong nsp;
507
508                         /*
509                          * the inital ramdisk does not need to be within
510                          * CFG_BOOTMAPSZ as it is not accessed until after
511                          * the mm system is initialised.
512                          *
513                          * do the stack bottom calculation again and see if
514                          * the initrd will fit just below the monitor stack
515                          * bottom without overwriting the area allocated
516                          * above for command line args and board info.
517                          */
518                         asm( "mr %0,1": "=r"(nsp) : );
519                         nsp -= 2048;            /* just to be sure */
520                         nsp &= ~0xF;
521                         if (nsp > initrd_high)  /* limit as specified */
522                                 nsp = initrd_high;
523                         nsp -= len;
524                         nsp &= ~(4096 - 1);     /* align on page */
525                         if (nsp >= sp)
526                                 initrd_start = nsp;
527                 }
528
529                 SHOW_BOOT_PROGRESS (12);
530 #ifdef  DEBUG
531                 printf ("## initrd at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n",
532                         data, data + len - 1, len, len);
533 #endif
534                 initrd_end    = initrd_start + len;
535                 printf ("   Loading Ramdisk to %08lx, end %08lx ... ",
536                         initrd_start, initrd_end);
537 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
538                 {
539                         size_t l = len;
540                         void *to = (void *)initrd_start;
541                         void *from = (void *)data;
542
543                         while (l > 0) {
544                                 size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
545                                 WATCHDOG_RESET();
546                                 memmove (to, from, tail);
547                                 to += tail;
548                                 from += tail;
549                                 l -= tail;
550                         }
551                 }
552 #else   /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
553                 memmove ((void *)initrd_start, (void *)data, len);
554 #endif  /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
555                 printf ("OK\n");
556         } else {
557                 initrd_start = 0;
558                 initrd_end = 0;
559         }
560
561 #ifdef DEBUG
562         printf ("## Transferring control to Linux (at address %08lx) ...\n",
563                 (ulong)kernel);
564 #endif
565         SHOW_BOOT_PROGRESS (15);
566
567 #ifdef CFG_INIT_RAM_LOCK
568         unlock_ram_in_cache();
569 #endif
570         /*
571          * Linux Kernel Parameters:
572          *   r3: ptr to board info data
573          *   r4: initrd_start or 0 if no initrd
574          *   r5: initrd_end - unused if r4 is 0
575          *   r6: Start of command line string
576          *   r7: End   of command line string
577          */
578         (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
579 }
580 #endif /* CONFIG_ARM */
581
582 static void
583 do_bootm_netbsd (cmd_tbl_t *cmdtp, int flag,
584                 int     argc, char *argv[],
585                 ulong   addr,
586                 ulong   *len_ptr,
587                 int     verify)
588 {
589         DECLARE_GLOBAL_DATA_PTR;
590
591         image_header_t *hdr = &header;
592
593         void    (*loader)(bd_t *, image_header_t *, char *, char *);
594         image_header_t *img_addr;
595         char     *consdev;
596         char     *cmdline;
597
598
599         /*
600          * Booting a (NetBSD) kernel image
601          *
602          * This process is pretty similar to a standalone application:
603          * The (first part of an multi-) image must be a stage-2 loader,
604          * which in turn is responsible for loading & invoking the actual
605          * kernel.  The only differences are the parameters being passed:
606          * besides the board info strucure, the loader expects a command
607          * line, the name of the console device, and (optionally) the
608          * address of the original image header.
609          */
610
611         img_addr = 0;
612         if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1]))
613                 img_addr = (image_header_t *) addr;
614
615
616         consdev = "";
617 #if   defined (CONFIG_8xx_CONS_SMC1)
618         consdev = "smc1";
619 #elif defined (CONFIG_8xx_CONS_SMC2)
620         consdev = "smc2";
621 #elif defined (CONFIG_8xx_CONS_SCC2)
622         consdev = "scc2";
623 #elif defined (CONFIG_8xx_CONS_SCC3)
624         consdev = "scc3";
625 #endif
626
627         if (argc > 2) {
628                 ulong len;
629                 int   i;
630
631                 for (i=2, len=0 ; i<argc ; i+=1)
632                         len += strlen (argv[i]) + 1;
633                 cmdline = malloc (len);
634
635                 for (i=2, len=0 ; i<argc ; i+=1) {
636                         if (i > 2)
637                                 cmdline[len++] = ' ';
638                         strcpy (&cmdline[len], argv[i]);
639                         len += strlen (argv[i]);
640                 }
641         } else if ((cmdline = getenv("bootargs")) == NULL) {
642                 cmdline = "";
643         }
644
645         loader = (void (*)(bd_t *, image_header_t *, char *, char *)) hdr->ih_ep;
646
647         printf ("## Transferring control to NetBSD stage-2 loader (at address %08lx) ...\n",
648                 (ulong)loader);
649
650         SHOW_BOOT_PROGRESS (15);
651
652         /*
653          * NetBSD Stage-2 Loader Parameters:
654          *   r3: ptr to board info data
655          *   r4: image address
656          *   r5: console device
657          *   r6: boot args string
658          */
659         (*loader) (gd->bd, img_addr, consdev, cmdline);
660 }
661
662 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
663 int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
664 {
665         int rcode = 0;
666 #ifndef CFG_HUSH_PARSER
667         if (run_command (getenv ("bootcmd"), flag) < 0) rcode = 1;
668 #else
669         if (parse_string_outer(getenv("bootcmd"),
670                 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0 ) rcode = 1;
671 #endif
672         return rcode;
673 }
674 #endif
675
676 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
677 int do_iminfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
678 {
679         int     arg;
680         ulong   addr;
681         int     rcode=0;
682
683         if (argc < 2) {
684                 return image_info (load_addr);
685         }
686
687         for (arg=1; arg <argc; ++arg) {
688                 addr = simple_strtoul(argv[arg], NULL, 16);
689                 if (image_info (addr) != 0) rcode = 1;
690         }
691         return rcode;
692 }
693
694 static int image_info (ulong addr)
695 {
696         ulong   data, len, checksum;
697         image_header_t *hdr = &header;
698
699         printf ("\n## Checking Image at %08lx ...\n", addr);
700
701         /* Copy header so we can blank CRC field for re-calculation */
702         memmove (&header, (char *)addr, sizeof(image_header_t));
703
704         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
705                 printf ("   Bad Magic Number\n");
706                 return 1;
707         }
708
709         data = (ulong)&header;
710         len  = sizeof(image_header_t);
711
712         checksum = ntohl(hdr->ih_hcrc);
713         hdr->ih_hcrc = 0;
714
715         if (crc32 (0, (char *)data, len) != checksum) {
716                 printf ("   Bad Header Checksum\n");
717                 return 1;
718         }
719
720         /* for multi-file images we need the data part, too */
721         print_image_hdr ((image_header_t *)addr);
722
723         data = addr + sizeof(image_header_t);
724         len  = ntohl(hdr->ih_size);
725
726         printf ("   Verifying Checksum ... ");
727         if (crc32 (0, (char *)data, len) != ntohl(hdr->ih_dcrc)) {
728                 printf ("   Bad Data CRC\n");
729                 return 1;
730         }
731         printf ("OK\n");
732         return 0;
733 }
734 #endif  /* CFG_CMD_IMI */
735
736 void
737 print_image_hdr (image_header_t *hdr)
738 {
739 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
740         time_t timestamp = (time_t)ntohl(hdr->ih_time);
741         struct rtc_time tm;
742 #endif
743
744         printf ("   Image Name:   %.*s\n", IH_NMLEN, hdr->ih_name);
745 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
746         to_tm (timestamp, &tm);
747         printf ("   Created:      %4d-%02d-%02d  %2d:%02d:%02d UTC\n",
748                 tm.tm_year, tm.tm_mon, tm.tm_mday,
749                 tm.tm_hour, tm.tm_min, tm.tm_sec);
750 #endif  /* CFG_CMD_DATE, CONFIG_TIMESTAMP */
751         printf ("   Image Type:   "); print_type(hdr); printf ("\n");
752         printf ("   Data Size:    %d Bytes = ", ntohl(hdr->ih_size));
753         print_size (ntohl(hdr->ih_size), "\n");
754         printf ("   Load Address: %08x\n", ntohl(hdr->ih_load));
755         printf ("   Entry Point:  %08x\n", ntohl(hdr->ih_ep));
756
757         if (hdr->ih_type == IH_TYPE_MULTI) {
758                 int i;
759                 ulong len;
760                 ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t));
761
762                 printf ("   Contents:\n");
763                 for (i=0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) {
764                         printf ("   Image %d: %8ld Bytes = ", i, len);
765                         print_size (len, "\n");
766                 }
767         }
768 }
769
770
771 static void
772 print_type (image_header_t *hdr)
773 {
774         char *os, *arch, *type, *comp;
775
776         switch (hdr->ih_os) {
777         case IH_OS_INVALID:     os = "Invalid OS";              break;
778         case IH_OS_NETBSD:      os = "NetBSD";                  break;
779         case IH_OS_LINUX:       os = "Linux";                   break;
780         case IH_OS_VXWORKS:     os = "VxWorks";                 break;
781         case IH_OS_QNX:         os = "QNX";                     break;
782         case IH_OS_U_BOOT:      os = "U-Boot";                  break;
783         default:                os = "Unknown OS";              break;
784         }
785
786         switch (hdr->ih_arch) {
787         case IH_CPU_INVALID:    arch = "Invalid CPU";           break;
788         case IH_CPU_ALPHA:      arch = "Alpha";                 break;
789         case IH_CPU_ARM:        arch = "ARM";                   break;
790         case IH_CPU_I386:       arch = "Intel x86";             break;
791         case IH_CPU_IA64:       arch = "IA64";                  break;
792         case IH_CPU_MIPS:       arch = "MIPS";                  break;
793         case IH_CPU_MIPS64:     arch = "MIPS 64 Bit";           break;
794         case IH_CPU_PPC:        arch = "PowerPC";               break;
795         case IH_CPU_S390:       arch = "IBM S390";              break;
796         case IH_CPU_SH:         arch = "SuperH";                break;
797         case IH_CPU_SPARC:      arch = "SPARC";                 break;
798         case IH_CPU_SPARC64:    arch = "SPARC 64 Bit";          break;
799         default:                arch = "Unknown Architecture";  break;
800         }
801
802         switch (hdr->ih_type) {
803         case IH_TYPE_INVALID:   type = "Invalid Image";         break;
804         case IH_TYPE_STANDALONE:type = "Standalone Program";    break;
805         case IH_TYPE_KERNEL:    type = "Kernel Image";          break;
806         case IH_TYPE_RAMDISK:   type = "RAMDisk Image";         break;
807         case IH_TYPE_MULTI:     type = "Multi-File Image";      break;
808         case IH_TYPE_FIRMWARE:  type = "Firmware";              break;
809         case IH_TYPE_SCRIPT:    type = "Script";                break;
810         default:                type = "Unknown Image";         break;
811         }
812
813         switch (hdr->ih_comp) {
814         case IH_COMP_NONE:      comp = "uncompressed";          break;
815         case IH_COMP_GZIP:      comp = "gzip compressed";       break;
816         case IH_COMP_BZIP2:     comp = "bzip2 compressed";      break;
817         default:                comp = "unknown compression";   break;
818         }
819
820         printf ("%s %s %s (%s)", arch, os, type, comp);
821 }
822
823 #define ZALLOC_ALIGNMENT        16
824
825 static void *zalloc(void *x, unsigned items, unsigned size)
826 {
827         void *p;
828
829         size *= items;
830         size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
831
832         p = malloc (size);
833
834         return (p);
835 }
836
837 static void zfree(void *x, void *addr, unsigned nb)
838 {
839         free (addr);
840 }
841
842 #define HEAD_CRC        2
843 #define EXTRA_FIELD     4
844 #define ORIG_NAME       8
845 #define COMMENT         0x10
846 #define RESERVED        0xe0
847
848 #define DEFLATED        8
849
850 int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
851 {
852         z_stream s;
853         int r, i, flags;
854
855         /* skip header */
856         i = 10;
857         flags = src[3];
858         if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
859                 printf ("Error: Bad gzipped data\n");
860                 return (-1);
861         }
862         if ((flags & EXTRA_FIELD) != 0)
863                 i = 12 + src[10] + (src[11] << 8);
864         if ((flags & ORIG_NAME) != 0)
865                 while (src[i++] != 0)
866                         ;
867         if ((flags & COMMENT) != 0)
868                 while (src[i++] != 0)
869                         ;
870         if ((flags & HEAD_CRC) != 0)
871                 i += 2;
872         if (i >= *lenp) {
873                 printf ("Error: gunzip out of data in header\n");
874                 return (-1);
875         }
876
877         s.zalloc = zalloc;
878         s.zfree = zfree;
879 #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
880         s.outcb = (cb_func)WATCHDOG_RESET;
881 #else
882         s.outcb = Z_NULL;
883 #endif  /* CONFIG_HW_WATCHDOG */
884
885         r = inflateInit2(&s, -MAX_WBITS);
886         if (r != Z_OK) {
887                 printf ("Error: inflateInit2() returned %d\n", r);
888                 return (-1);
889         }
890         s.next_in = src + i;
891         s.avail_in = *lenp - i;
892         s.next_out = dst;
893         s.avail_out = dstlen;
894         r = inflate(&s, Z_FINISH);
895         if (r != Z_OK && r != Z_STREAM_END) {
896                 printf ("Error: inflate() returned %d\n", r);
897                 return (-1);
898         }
899         *lenp = s.next_out - (unsigned char *) dst;
900         inflateEnd(&s);
901
902         return (0);
903 }
904
905 #if (CONFIG_COMMANDS & CFG_CMD_ELF)
906 static void
907 do_bootm_vxworks (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
908                   ulong addr, ulong *len_ptr, int verify)
909 {
910         image_header_t *hdr = &header;
911         char str[80];
912
913         sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */
914         setenv("loadaddr", str);
915         do_bootvx(cmdtp, 0, 0, NULL);
916 }
917
918 static void
919 do_bootm_qnxelf (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
920                  ulong addr, ulong *len_ptr, int verify)
921 {
922         image_header_t *hdr = &header;
923         char *local_args[2];
924         char str[16];
925
926         sprintf(str, "%x", hdr->ih_ep); /* write entry-point into string */
927         local_args[0] = argv[0];
928         local_args[1] = str;    /* and provide it via the arguments */
929         do_bootelf(cmdtp, 0, 2, local_args);
930 }
931 #endif /* CFG_CMD_ELF */