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